size: printing size of style
[treecutter.git] / xinclude / address.py
index fd7e0002589cd843964b5d73fc0d8338bd9bea25..6a30d7accc13006f17d337ff30ddc6a2c86f8c18 100755 (executable)
@@ -2,15 +2,18 @@
 # -*- 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
 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
@@ -21,18 +24,6 @@ ZOOMRANGE = range(1, 18)
 # tile size
 TS = 256
 
-DB_NS="http://docbook.org/ns/docbook"
-DB = "{%s}" % DB_NS
-XI_NS="http://www.w3.org/2001/XInclude"
-XI = "{%s}" % XI_NS
-XLINK_NS="http://www.w3.org/1999/xlink"
-XLINK = "{%s}" % XLINK_NS
-HTML_NS="http://www.w3.org/1999/xhtml"
-HTML = "{%s}" % HTML_NS
-NSMAP = {None : DB_NS,
-         'xlink' : XLINK_NS}
-
-
 h = Http(".cache")
 
 class Coord(object):
@@ -56,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)
@@ -90,101 +68,148 @@ 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):
-        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
 
+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"""
-    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',
-                   '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):
-        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):
@@ -198,16 +223,17 @@ def mark(image, coord):
     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)):
-        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
@@ -216,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)
 
+        ul = Coord(maxlat,minlon).direct(315, hyp)
+
         ul = (uld['lat2'],uld['lon2'])
         ur = (urd['lat2'],urd['lon2'])
         ll = (lld['lat2'],lld['lon2'])
@@ -271,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")
+
+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))