2 # -*- coding: utf-8 -*-
6 from httplib2 import Http
10 from PIL import Image, ImageDraw
11 from StringIO import StringIO
12 from geohash import encode
13 from geographiclib.geodesic import Geodesic
16 EC = 40075016.686 # meter
18 ER = 6372798.2 # meter
19 # Availible zoom levels in OSM
20 ZOOMRANGE = range(1, 18)
27 def lontile(lon, zoom):
28 tile = ((lon + 180) / 360) * (2**zoom)
31 def lattile(lat, zoom):
32 tile = (1 - log(tan(lat * pi/180) + 1 / cos(lat* pi/180)) / pi) /2 * 2**zoom
33 # tile = (1-log(tan(radians(lat))+1/cos(radians(lat)))/pi)/2*2**zoom
36 def coordtile(coord, zoom):
37 x = lontile(coord[1],zoom)
38 y = lattile(coord[0],zoom)
42 return 'http://tile.openstreetmap.org/%s/%s/%s.png' % (z,x,y)
46 x = int(floor(lontile(coord[1],z)))
47 y = int(floor(lattile(coord[0],z)))
50 def offset(coord, zoom):
52 x = lontile(coord[1],z)
53 y = lattile(coord[0],z)
54 xo = int(floor((x-floor(x))*TS))
55 yo = int(floor((y-floor(y))*TS))
59 res = Geodesic.WGS84.Inverse(p1[0], p1[1], p2[0], p2[1])
62 def geocode(address,country=None):
63 params = { 'q': address,
70 params['countrycodes'] = country
72 base_url = 'http://nominatim.openstreetmap.org/search?%s'
73 url = base_url % urllib.urlencode(params)
74 resp, content = h.request(url)
77 root = etree.fromstring(content)
79 # print "%s" % (address)
82 for element in root.iter("place"):
83 lat = element.get("lat")
84 lon = element.get("lon")
85 # print(" : %s,%s" % (lat, lon))
87 if not lat or not lon:
90 return (float(lat),float(lon))
92 def mark(image, coord):
93 draw = ImageDraw.Draw(image)
96 bbox = (x-r, y-r, x+r, y+r)
97 draw.ellipse(bbox, outline="red")
99 def mapimage(coords, zoom=15,size=(TS,TS)):
102 filename = encode(co[0],co[1])+'.png'
103 if path.isfile(filename):
104 if path.getctime(filename) > time.time() - 60*60*24*2:
106 im = Image.new("RGB", size, None)
107 center = (size[0]/2, size[1]/2)
108 nst = ceil(center[0]-TS/2)/TS
109 ewt = ceil(center[1]-TS/2)/TS
110 x, y = offset(co,zoom)
111 (ns, ew) = coordtile(co,zoom)
124 ul = (ns-nst-n, ew-ewt-e)
125 lr = (ns+nst+s, ew+ewt+w)
126 lattiles = range(int(ul[0]),int(lr[0])+1)
127 lontiles = range(int(ul[1]),int(lr[1])+1)
129 size = (len(lontiles)*TS,len(lattiles)*TS)
130 grid = Image.new("RGB", size, None)
132 for yi, y in enumerate(lattiles):
133 for xi, x in enumerate(lontiles):
137 request, content = h.request(url)
138 img = Image.open(StringIO(content))
141 t = coordtile(co,zoom)
143 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
144 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
146 gridc = grid.crop((xp-TS/2,yp-TS/2,xp+TS/2,yp+TS/2))
154 minlat = min(minlat,c[0])
155 maxlat = max(maxlat,c[0])
156 minlon = min(minlon,c[1])
157 maxlon = max(maxlon,c[1])
158 # Find minimal bounding box and expand it 5%
159 hyp = distance((maxlat,minlon),(minlat,maxlon))
161 uld = Geodesic.WGS84.Direct(maxlat, minlon, 315, hyp)
162 urd = Geodesic.WGS84.Direct(maxlat, maxlon, 45, hyp)
163 lld = Geodesic.WGS84.Direct(minlat, minlon, 225, hyp)
164 lrd = Geodesic.WGS84.Direct(minlat, maxlon, 135, hyp)
166 ul = (uld['lat2'],uld['lon2'])
167 ur = (urd['lat2'],urd['lon2'])
168 ll = (lld['lat2'],lld['lon2'])
169 lr = (lrd['lat2'],lrd['lon2'])
170 top = distance(ul,ur)
171 bottom = distance(ll,lr)
172 left = distance(ul,ll)
173 right = distance(ur,lr)
174 # m_per_pix = EC*abs(cos(lat))/2**(zoomlevel+8)
175 # m_per_pix = ER*2*pi*abs(cos(lat))/2**(zoomlevel+8)
176 for zoom in range(1,18):
177 t = 2**(zoom)*TS/(ER*2*pi*abs(cos(ul[0])))
180 b = 2**(zoom)*TS/(ER*2*pi*abs(cos(ll[0])))
183 # print "Zoom: %s : %s %s %s %s" % (zoom, toppix, bottompix, leftpix, rightpix)
184 if max(toppix,bottompix,leftpix,rightpix) > TS*4:
186 # print "Zoom to use : %s" % (zoom)
187 ult = coordtile(ul,zoom)
188 lrt = coordtile(lr,zoom)
189 lattiles = range(int(ult[0]),int(lrt[0])+1)
190 lontiles = range(int(ult[1]),int(lrt[1])+1)
191 size = (len(lontiles)*TS,len(lattiles)*TS)
192 grid = Image.new("RGB", size, None)
194 for yi, y in enumerate(lattiles):
195 for xi, x in enumerate(lontiles):
199 request, content = h.request(url)
200 img = Image.open(StringIO(content))
204 t = coordtile(c,zoom)
206 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
207 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
210 t = coordtile(ul,zoom)
212 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
213 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
214 t = coordtile(lr,zoom)
216 ypl = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
217 xpl = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
218 gridc = grid.crop((xp,yp,xpl,ypl))
220 # gridc.save("cap-un.png")