From: Fredrik Unger Date: Fri, 9 Nov 2012 10:39:55 +0000 (+0100) Subject: Objectified Coord and Address methods, made it main callable X-Git-Url: https://source.tree.se/git?p=treecutter.git;a=commitdiff_plain;h=676fd9d928d47c787b38ca66011de179ae034beb Objectified Coord and Address methods, made it main callable Rewrote the classes to use internal data for their methods, fixed sizing of the png images (made the size really settable). Geocoding does try several times with different strings before failing. Address is also now directly callable for simple addresses, without contact. --- diff --git a/xinclude/address.py b/xinclude/address.py index 8ce6a6a..c99f51a 100755 --- a/xinclude/address.py +++ b/xinclude/address.py @@ -2,10 +2,11 @@ # -*- coding: utf-8 -*- import time +import sys from os import path from httplib2 import Http -import urllib -from math import * +from urllib import urlencode +from math import log,tan,pi,cos,radians,ceil,floor from lxml import etree from lxml.builder import ElementMaker from PIL import Image, ImageDraw @@ -46,31 +47,18 @@ class Coord(object): out += u''' %d°%2d'%05.2f"%s''' % ( deg,mnt,sec,'E') return out - def lontile(lon, zoom): - tile = ((lon + 180) / 360) * (2**zoom) + def lontile(self, zoom): + tile = ((self.longitude + 180) / 360) * (2**zoom) return tile - def lattile(lat, zoom): - tile = (1 - log(tan(lat * pi/180) + 1 / cos(lat* pi/180)) / pi) /2 * 2**zoom - # tile = (1-log(tan(radians(lat))+1/cos(radians(lat)))/pi)/2*2**zoom + def lattile(self, zoom): + rad = radians(self.latitude) + tile = (1-log(tan(rad)+1/cos(rad))/pi)/2*2**zoom return tile - def coordtile(coord, zoom): - x = lontile(coord[1],zoom) - y = lattile(coord[0],zoom) - return (y,x) - - def tile(x,y,z): - return 'http://tile.openstreetmap.org/%s/%s/%s.png' % (z,x,y) - - def link(coord,zoom): - (x, y) = coordtile(coord,zoom) - x = int(floor(x)) - y = int(floor(y)) - return tile(x,y,zoom) - - def offset(coord, zoom): - (x, y) = coordtile(coord,zoom) + def offset(self,zoom): + x = self.lontile(zoom) + y = self.lattile(zoom) xo = int(floor((x-floor(x))*TS)) yo = int(floor((y-floor(y))*TS)) return (xo, yo) @@ -80,53 +68,54 @@ class Coord(object): point.latitude, point.longitude) return res['s12'] - def png(self,zoom=15,size=(TS,TS)): + def direct(self, direction, lenght): + point = Geodesic.WGS84.Direct(self.latitude, self.longitude, + direction, length) + return self.__class__(point['lat2'],point['lon2']) + + def png(self,zoom=15,size=(400,150)): filename = encode(self.latitude, self.longitude)+'.png' - if path.isfile(filename): - if path.getctime(filename) > time.time() - 60*60*24*2: - return +# if path.isfile(filename): +# if path.getctime(filename) > time.time() - 60*60*24*2: +# return im = Image.new("RGB", size, None) - center = (size[0]/2, size[1]/2) - nst = ceil(center[0]-TS/2)/TS - ewt = ceil(center[1]-TS/2)/TS - x, y = offset(co,zoom) - (ns, ew) = coordtile(co,zoom) - if x < TS/2: - e = 1 - w = 0 - if x > TS/2: - e = 0 - w = 1 - if y < TS/2: - n = 1 - s = 0 - if y > TS/2: - n = 0 - s = 1 - ul = (ns-nst-n, ew-ewt-e) - lr = (ns+nst+s, ew+ewt+w) - lattiles = range(int(ul[0]),int(lr[0])+1) - lontiles = range(int(ul[1]),int(lr[1])+1) -# url = link(c,zoom) - size = (len(lontiles)*TS,len(lattiles)*TS) - grid = Image.new("RGB", size, None) + + ew = int(self.lontile(zoom)) + ns = int(self.lattile(zoom)) + + (xo, yo) = self.offset(zoom) + et = int(floor((xo - ceil(size[0]/2))/TS)) + nt = int(floor((yo - ceil(size[1]/2))/TS)) + wt = int(floor((xo + ceil(size[0]/2))/TS)) + st = int(floor((yo + ceil(size[1]/2))/TS)) + + lontiles = range(ew+et,ew+wt+1) + lattiles = range(ns+nt,ns+st+1) + imsize = (len(lontiles)*TS,len(lattiles)*TS) + grid = Image.new("RGB", imsize, None) for yi, y in enumerate(lattiles): for xi, x in enumerate(lontiles): - url = tile(x,y,zoom) - time.sleep(1) + url = 'http://tile.openstreetmap.org/%s/%s/%s.png' % (zoom,x,y) request, content = h.request(url) img = Image.open(StringIO(content)) +# dr = ImageDraw.Draw(img) +# dr.rectangle([0,0,TS,TS], outline=0) box = (xi*TS, yi*TS) grid.paste(img, box) - t = coordtile(co,zoom) - o = offset(co,zoom) - yp = [i for i,x in enumerate(lattiles) if x == int(t[0])][0]*TS+o[1] - xp = [i for i,x in enumerate(lontiles) if x == int(t[1])][0]*TS+o[0] + + yp = [i for i,j in enumerate(lattiles) if j == int(ns)][0]*TS+yo + xp = [i for i,j in enumerate(lontiles) if j == int(ew)][0]*TS+xo mark(grid, (xp,yp)) - gridc = grid.crop((xp-TS/2,yp-TS/2,xp+TS/2,yp+TS/2)) + xc = int(ceil(size[0]/2)) + yc = int(ceil(size[1]/2)) + +# draw = ImageDraw.Draw(grid) +# draw.rectangle([xp-xc,yp-yc,xp+xc,yp+yc], outline="red") + gridc = grid.crop((xp-xc,yp-yc,xp+xc,yp+yc)) gridc.save(filename) def db_xml(self): + self.png() img = encode(self.latitude, self.longitude)+'.png' phr = "geo:"+str(self.latitude)+","+str(self.longitude) @@ -135,46 +124,75 @@ class Coord(object): db.inlinemediaobject( db.imageobject(db.imagedata( fileref=img, - format='PNG')) + format='PNG')), db.textobject(db.phrase(phr)) ), - db.para(self.dms()) + self.dms(), **{const.XLINK+"href": self.osmlink()})) return uri class Address(object): """Address object to contain everything known about an address""" - def __init__(self,address): - self._address_string = address - self._coord = None + def __init__(self,street=None,postcode=None,city=None,country=None): + self.name = None + self.street = street + self.postcode = postcode + self.city = city + self.country = country + self.phone = '' + self.coord = None - def geocode(self,country=None): - params = { 'q': self._address_string, - 'addressdetails': 1, + def geocode(self): + base_url = 'http://nominatim.openstreetmap.org/search?%s' + params = { 'addressdetails': 1, 'limit': 1, 'format': 'xml', 'polygon': 0 } - if country: - params['countrycodes'] = country + if self.country: + t = etree.parse('/usr/share/xml/iso-codes/iso_3166.xml') + r = t.xpath('//iso_3166_entry[@name="'+self.country+'"]') + if len(r)==1: + params['countrycodes'] = r[0].get("alpha_2_code") - base_url = 'http://nominatim.openstreetmap.org/search?%s' - url = base_url % urllib.urlencode(params) - resp, content = h.request(url) - root = etree.fromstring(content) - place = root.find("place") - if place is not None: - print (etree.tostring(root, pretty_print=True)) - self._coord=Coord(place.get("lat"),place.get("lon")) - return 1 - else: - print resp - print content - return 0 + addrlist=[] + if self.name and len(self.name)>0: + addrlist.append(u''+self.name+', '+self.street+', '+self.city) + addrlist.append(u''+self.street+', '+self.postcode+', '+self.city) + addrlist.append(u''+self.street+', '+self.city) + + for addr in addrlist: + params['q'] = addr.encode('utf-8') + url = base_url % urlencode(params) + time.sleep(1) + resp, content = h.request(url) + root = etree.fromstring(content) + places = int(root.xpath('count(//place[@place_id])')) + if places == 1: + place = root.find("place") + self.coord=Coord(place.get("lat"),place.get("lon")) + return + sys.stderr.write(u'FAILURE: Did not find:\n') + sys.stderr.write(addrlist[0].encode('utf-8')) + sys.stderr.write(url) + + def add_phone(self, phone): + self.phone = phone + + def set_name(self, name): + self.name = name def db_xml(self): - return self._coord.db_xml() + db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP) + adr = db.address(db.street(self.street), + db.postcode(self.postcode), + db.city(self.city), + db.country(self.country), + db.phone(self.phone), + self.coord.db_xml()) +# type=self.type, + return adr def distance(p1, p2): @@ -261,3 +279,24 @@ def mapimages(coords, zoom=15,size=(TS,TS)): gridc = grid.crop((xp,yp,xpl,ypl)) gridc.show() # gridc.save("cap-un.png") + +if __name__ == "__main__": + for arg in sys.argv[1:]: + al = arg.split("=") + if al[0] == "lang": + lang = al[1] + if al[0] == "xptr": + argument = al[1].decode('utf-8') + + addrlist = argument.split(',') + addrfmt = "street,postcode,city,country" + adict = addrfmt.split(',') + argdict = dict(zip(adict,addrlist)) + addr = Address(**argdict) + addr.geocode() + axml = addr.db_xml() +# clean_db(axml) + + #print(etree.tostring(cxml, pretty_print=True)) + #sys.stdout.write(out.encode('utf-8')) + sys.stdout.write(etree.tostring(axml,encoding='UTF-8',pretty_print=False))