address.py: changed update check of address string
[treecutter.git] / xinclude / address.py
index 3b7ff38a3754fe945d227280d133758de70b574d..6a30d7accc13006f17d337ff30ddc6a2c86f8c18 100755 (executable)
@@ -2,15 +2,18 @@
 # -*- coding: utf-8 -*-
 
 import time
 # -*- coding: utf-8 -*-
 
 import time
+import sys
 from os import path
 from httplib2 import Http
 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 import etree
+from lxml.builder import ElementMaker
 from PIL import Image, ImageDraw
 from StringIO import StringIO
 from geohash import encode
 from geographiclib.geodesic import Geodesic
 from PIL import Image, ImageDraw
 from StringIO import StringIO
 from geohash import encode
 from geographiclib.geodesic import Geodesic
+from treecutter import constants as const
 
 # EC Equator lenght
 EC = 40075016.686 # meter
 
 # EC Equator lenght
 EC = 40075016.686 # meter
@@ -21,7 +24,6 @@ ZOOMRANGE = range(1, 18)
 # tile size
 TS = 256
 
 # tile size
 TS = 256
 
-
 h = Http(".cache")
 
 class Coord(object):
 h = Http(".cache")
 
 class Coord(object):
@@ -45,131 +47,169 @@ class Coord(object):
         out +=  u''' %d°%2d'%05.2f"%s''' % ( deg,mnt,sec,'E')
         return out
 
         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
 
         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
 
         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)
 
         xo = int(floor((x-floor(x))*TS))
         yo = int(floor((y-floor(y))*TS))
         return (xo, yo)
 
-    def png(self,zoom=15,size=(TS,TS)):
+    def distance(self, point):
+        res = Geodesic.WGS84.Inverse(self.latitude, self.longitude,
+                                     point.latitude, point.longitude)
+        return res['s12']
+
+    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'
         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)
         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):
         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))
                 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)
                 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))
         mark(grid, (xp,yp))
-        gridc = grid.crop((xp-TS/2,yp-TS/2,xp+TS/2,yp+TS/2))
-        gridc.save(filename)
+        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):
 
     def db_xml(self):
-        uri = etree.Element(DB+'uri',nsmap=NSMAP)
-        ln  = etree.SubElement(uri,  DB+'link')
-        ln.set(XLINK+'href',self.osmlink())
-        imo  = etree.SubElement(ln,  DB+'inlinemediaobject')
-        io   = etree.SubElement(imo, DB+'imageobject', condition="web")
-        idat = etree.SubElement(io , DB+'imagedata',
-                                fileref=encode(self.latitude, self.longitude)+'.png',
-                                format='PNG')
-        to   = etree.SubElement(imo, DB+'textobject')
-        ph   = etree.SubElement(to,  DB+'phrase')
-        ph.text = "geo:"+str(self.latitude)+","+str(self.longitude)
-        para = etree.SubElement(ln,  DB+'para')
-        para.text = self.dms()
+        self.png()
+        img = encode(self.latitude, self.longitude)+'.png'
+        phr = "geo:"+str(self.latitude)+","+str(self.longitude)
+
+        db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP)
+        uri = db.uri(db.link(
+                db.inlinemediaobject(
+                    db.imageobject(db.imagedata(
+                            fileref=img,
+                            format='PNG')),
+                    db.textobject(db.phrase(phr))
+                    ),
+                self.dms(),
+                **{const.XLINK+"href": self.osmlink()}))
         return uri
 
         return uri
 
+def c(s):
+    return s or ''
+
+def s(s,n):
+    if n is not None:
+        return s or n.text
+    return s
+
+
 class Address(object):
     """Address object to contain everything known about an address"""
 class Address(object):
     """Address object to contain everything known about an address"""
-    def __init__(self,address):
-        self._address_string = address
-        self._root = etree.Element(DB+'address',nsmap=NSMAP)
-        self._coord = None
-
-    def geocode(self,country=None):
-        params = { 'q': self._address_string,
-                   'addressdetails': 1,
+    def __init__(self,street=None,postcode=None,city=None,country=None):
+        self.street = street
+        self.postcode = postcode
+        self.city = city
+        self.country = country
+        self.country_code = None
+        self.phone = None
+        self.name = None
+        self.coord = None
+
+
+    def geocode(self, language='en'):
+        base_url = 'http://nominatim.openstreetmap.org/search?%s'
+        params = { 'addressdetails': 1,
                    'limit': 1,
                    'format': 'xml',
                    'limit': 1,
                    'format': 'xml',
-                   'polygon': 0 }
+                   'polygon': 0,
+                   'accept-language': language}
 
 
-        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:
+                self.country_code = r[0].get("alpha_2_code")
+        if self.country_code:
+            params['countrycodes'] = self.country_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=[]
+        addrlist.append(u''+c(self.name)+', '+c(self.street)+', '+c(self.city))
+        addrlist.append(u''+c(self.street)+', '+c(self.postcode)+', '+c(self.city))
+        addrlist.append(u''+c(self.street)+', '+c(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")
+#                print etree.tostring(place,encoding='UTF-8',pretty_print=True)
+                self.postcode = s(self.postcode,place.find("postcode"))
+                self.city = s(self.city,place.find("city"))
+                self.country = s(self.country,place.find("country"))
+                self.country_code = s(self.country_code,place.find("country_code"))
+                self.coord=Coord(place.get("lat"),place.get("lon"))
+                return
+
+    def add_phone(self, phone):
+        self.phone = phone
+
+    def set_name(self, name):
+        self.name = name
 
     def db_xml(self):
 
     def db_xml(self):
-        return self._coord.db_xml()
+        db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP)
+        co = ''
+        if self.coord:
+            co = self.coord.db_xml()
+        adr = db.address(db.street(c(self.street)),
+                         db.postcode(c(self.postcode)),
+                         db.city(c(self.city)),
+                         db.country(c(self.country)),
+                         db.phone(c(self.phone)),
+                         co)
+#                       type=self.type,
+        return adr
 
 
 def distance(p1, p2):
 
 
 def distance(p1, p2):
@@ -183,16 +223,17 @@ def mark(image, coord):
     bbox = (x-r, y-r, x+r, y+r)
     draw.ellipse(bbox, outline="red")
 
     bbox = (x-r, y-r, x+r, y+r)
     draw.ellipse(bbox, outline="red")
 
+def box(image,box):
+    draw = ImageDraw.Draw(image)
+    draw.rectangle(box, outline="red")
+
 def mapimages(coords, zoom=15,size=(TS,TS)):
 def mapimages(coords, zoom=15,size=(TS,TS)):
-        minlat = 1000
-        maxlat = 0
-        minlon = 1000
-        maxlon = 0
-        for c in coords:
-            minlat = min(minlat,c[0])
-            maxlat = max(maxlat,c[0])
-            minlon = min(minlon,c[1])
-            maxlon = max(maxlon,c[1])
+
+        minlat = min(coords,key=attrgetter('latitude'))
+        maxlat = max(coords,key=attrgetter('latitude'))
+        minlon = min(coords,key=attrgetter('longitude'))
+        maxlon = max(coords,key=attrgetter('longitude'))
+
         # Find minimal bounding box and expand it 5%
         hyp = distance((maxlat,minlon),(minlat,maxlon))
         hyp = hyp*0.05
         # Find minimal bounding box and expand it 5%
         hyp = distance((maxlat,minlon),(minlat,maxlon))
         hyp = hyp*0.05
@@ -201,6 +242,8 @@ def mapimages(coords, zoom=15,size=(TS,TS)):
         lld =  Geodesic.WGS84.Direct(minlat, minlon, 225, hyp)
         lrd =  Geodesic.WGS84.Direct(minlat, maxlon, 135, hyp)
 
         lld =  Geodesic.WGS84.Direct(minlat, minlon, 225, hyp)
         lrd =  Geodesic.WGS84.Direct(minlat, maxlon, 135, hyp)
 
+        ul = Coord(maxlat,minlon).direct(315, hyp)
+
         ul = (uld['lat2'],uld['lon2'])
         ur = (urd['lat2'],urd['lon2'])
         ll = (lld['lat2'],lld['lon2'])
         ul = (uld['lat2'],uld['lon2'])
         ur = (urd['lat2'],urd['lon2'])
         ll = (lld['lat2'],lld['lon2'])
@@ -256,3 +299,24 @@ def mapimages(coords, zoom=15,size=(TS,TS)):
         gridc = grid.crop((xp,yp,xpl,ypl))
         gridc.show()
 #        gridc.save("cap-un.png")
         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))