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)
28 def __init__(self, lat, lon):
29 self.latitude = float(lat)
30 self.longitude = float(lon)
34 return "http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=18&layers=M"\
35 % (self.latitude,self.longitude)
40 mnt,sec = divmod(ns*3600,60)
41 deg,mnt = divmod(mnt,60)
42 out = u'''%d°%2d'%5.2f"%s''' % ( deg,mnt,sec,'N')
43 mnt,sec = divmod(ew*3600,60)
44 deg,mnt = divmod(mnt,60)
45 out += u''' %d°%2d'%05.2f"%s''' % ( deg,mnt,sec,'E')
48 def lontile(lon, zoom):
49 tile = ((lon + 180) / 360) * (2**zoom)
52 def lattile(lat, zoom):
53 tile = (1 - log(tan(lat * pi/180) + 1 / cos(lat* pi/180)) / pi) /2 * 2**zoom
54 # tile = (1-log(tan(radians(lat))+1/cos(radians(lat)))/pi)/2*2**zoom
57 def coordtile(coord, zoom):
58 x = lontile(coord[1],zoom)
59 y = lattile(coord[0],zoom)
63 return 'http://tile.openstreetmap.org/%s/%s/%s.png' % (z,x,y)
66 (x, y) = coordtile(coord,zoom)
71 def offset(coord, zoom):
72 (x, y) = coordtile(coord,zoom)
73 xo = int(floor((x-floor(x))*TS))
74 yo = int(floor((y-floor(y))*TS))
77 def png(self,zoom=15,size=(TS,TS)):
78 filename = encode(self.latitude, self.longitude)+'.png'
79 if path.isfile(filename):
80 if path.getctime(filename) > time.time() - 60*60*24*2:
82 im = Image.new("RGB", size, None)
83 center = (size[0]/2, size[1]/2)
84 nst = ceil(center[0]-TS/2)/TS
85 ewt = ceil(center[1]-TS/2)/TS
86 x, y = offset(co,zoom)
87 (ns, ew) = coordtile(co,zoom)
100 ul = (ns-nst-n, ew-ewt-e)
101 lr = (ns+nst+s, ew+ewt+w)
102 lattiles = range(int(ul[0]),int(lr[0])+1)
103 lontiles = range(int(ul[1]),int(lr[1])+1)
105 size = (len(lontiles)*TS,len(lattiles)*TS)
106 grid = Image.new("RGB", size, None)
107 for yi, y in enumerate(lattiles):
108 for xi, x in enumerate(lontiles):
111 request, content = h.request(url)
112 img = Image.open(StringIO(content))
115 t = coordtile(co,zoom)
117 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
118 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
120 gridc = grid.crop((xp-TS/2,yp-TS/2,xp+TS/2,yp+TS/2))
125 uri = etree.Element(DB+'uri',nsmap=NSMAP)
126 ln = etree.SubElement(uri, DB+'link')
127 ln.set(XLINK+'href',self.osmlink())
128 imo = etree.SubElement(ln, DB+'inlinemediaobject')
129 io = etree.SubElement(imo, DB+'imageobject', condition="web")
130 idat = etree.SubElement(io , DB+'imagedata',
131 fileref=encode(self.latitude, self.longitude)+'.png',
133 to = etree.SubElement(imo, DB+'textobject')
134 ph = etree.SubElement(to, DB+'phrase')
135 ph.text = "geo:"+str(self.latitude)+","+str(self.longitude)
136 para = etree.SubElement(ln, DB+'para')
137 para.text = self.dms()
140 class Address(object):
141 """Address object to contain everything known about an address"""
142 def __init__(self,address):
143 self._address_string = address
144 self._root = etree.Element(DB+'address',nsmap=NSMAP)
147 def geocode(self,country=None):
148 params = { 'q': self._address_string,
155 params['countrycodes'] = country
157 base_url = 'http://nominatim.openstreetmap.org/search?%s'
158 url = base_url % urllib.urlencode(params)
159 resp, content = h.request(url)
160 root = etree.fromstring(content)
161 place = root.find("place")
162 if place is not None:
163 print (etree.tostring(root, pretty_print=True))
164 self._coord=Coord(place.get("lat"),place.get("lon"))
172 return self._coord.db_xml()
175 def distance(p1, p2):
176 res = Geodesic.WGS84.Inverse(p1[0], p1[1], p2[0], p2[1])
179 def mark(image, coord):
180 draw = ImageDraw.Draw(image)
183 bbox = (x-r, y-r, x+r, y+r)
184 draw.ellipse(bbox, outline="red")
186 def mapimages(coords, zoom=15,size=(TS,TS)):
192 minlat = min(minlat,c[0])
193 maxlat = max(maxlat,c[0])
194 minlon = min(minlon,c[1])
195 maxlon = max(maxlon,c[1])
196 # Find minimal bounding box and expand it 5%
197 hyp = distance((maxlat,minlon),(minlat,maxlon))
199 uld = Geodesic.WGS84.Direct(maxlat, minlon, 315, hyp)
200 urd = Geodesic.WGS84.Direct(maxlat, maxlon, 45, hyp)
201 lld = Geodesic.WGS84.Direct(minlat, minlon, 225, hyp)
202 lrd = Geodesic.WGS84.Direct(minlat, maxlon, 135, hyp)
204 ul = (uld['lat2'],uld['lon2'])
205 ur = (urd['lat2'],urd['lon2'])
206 ll = (lld['lat2'],lld['lon2'])
207 lr = (lrd['lat2'],lrd['lon2'])
208 top = distance(ul,ur)
209 bottom = distance(ll,lr)
210 left = distance(ul,ll)
211 right = distance(ur,lr)
212 # m_per_pix = EC*abs(cos(lat))/2**(zoomlevel+8)
213 # m_per_pix = ER*2*pi*abs(cos(lat))/2**(zoomlevel+8)
214 for zoom in range(1,18):
215 t = 2**(zoom)*TS/(ER*2*pi*abs(cos(ul[0])))
218 b = 2**(zoom)*TS/(ER*2*pi*abs(cos(ll[0])))
221 # print "Zoom: %s : %s %s %s %s" % (zoom, toppix, bottompix, leftpix, rightpix)
222 if max(toppix,bottompix,leftpix,rightpix) > TS*4:
224 # print "Zoom to use : %s" % (zoom)
225 ult = coordtile(ul,zoom)
226 lrt = coordtile(lr,zoom)
227 lattiles = range(int(ult[0]),int(lrt[0])+1)
228 lontiles = range(int(ult[1]),int(lrt[1])+1)
229 size = (len(lontiles)*TS,len(lattiles)*TS)
230 grid = Image.new("RGB", size, None)
232 for yi, y in enumerate(lattiles):
233 for xi, x in enumerate(lontiles):
237 request, content = h.request(url)
238 img = Image.open(StringIO(content))
242 t = coordtile(c,zoom)
244 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
245 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
248 t = coordtile(ul,zoom)
250 yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
251 xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
252 t = coordtile(lr,zoom)
254 ypl = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1]
255 xpl = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0]
256 gridc = grid.crop((xp,yp,xpl,ypl))
258 # gridc.save("cap-un.png")