Objectified Coord and Address methods, made it main callable
[treecutter.git] / xinclude / address.py
index 8ce6a6a7b77c581068cb8974afdd21c18b5a5357..c99f51ad0e86bca424f21a1d613f77a7d26e268b 100755 (executable)
@@ -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))