# -*- 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
# tile size
TS = 256
-
h = Http(".cache")
-def lontile(lon, zoom):
- tile = ((lon + 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
- 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):
- z = zoom
- x = int(floor(lontile(coord[1],z)))
- y = int(floor(lattile(coord[0],z)))
- return tile(x,y,z)
-
-def offset(coord, zoom):
- z = zoom
- x = lontile(coord[1],z)
- y = lattile(coord[0],z)
- xo = int(floor((x-floor(x))*TS))
- yo = int(floor((y-floor(y))*TS))
- return (xo, yo)
+class Coord(object):
+ def __init__(self, lat, lon):
+ self.latitude = float(lat)
+ self.longitude = float(lon)
+ self.image = None
-def distance(p1, p2):
- res = Geodesic.WGS84.Inverse(p1[0], p1[1], p2[0], p2[1])
- return res['s12']
+ def osmlink(self):
+ return "http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=18&layers=M"\
+ % (self.latitude,self.longitude)
-def geocode(address,country=None):
- params = { 'q': address,
- 'addressdetails': 1,
- 'limit': 1,
- 'format': 'xml',
- 'polygon': 0 }
- time.sleep(1)
- if country:
- params['countrycodes'] = country
-
- base_url = 'http://nominatim.openstreetmap.org/search?%s'
- url = base_url % urllib.urlencode(params)
- resp, content = h.request(url)
-# print resp
-# print content
- root = etree.fromstring(content)
- etree.tostring(root)
-# print "%s" % (address)
- lat = None
- lon = None
- for element in root.iter("place"):
- lat = element.get("lat")
- lon = element.get("lon")
-# print(" : %s,%s" % (lat, lon))
- break
- if not lat or not lon:
- print resp
- print content
- return (float(lat),float(lon))
+ def dms(self):
+ ns = self.latitude
+ ew = self.longitude
+ mnt,sec = divmod(ns*3600,60)
+ deg,mnt = divmod(mnt,60)
+ out = u'''%d°%2d'%5.2f"%s''' % ( deg,mnt,sec,'N')
+ mnt,sec = divmod(ew*3600,60)
+ deg,mnt = divmod(mnt,60)
+ out += u''' %d°%2d'%05.2f"%s''' % ( deg,mnt,sec,'E')
+ return out
-def mark(image, coord):
- draw = ImageDraw.Draw(image)
- x, y = coord
- r = 5
- bbox = (x-r, y-r, x+r, y+r)
- draw.ellipse(bbox, outline="red")
+ def lontile(self, zoom):
+ tile = ((self.longitude + 180) / 360) * (2**zoom)
+ return tile
-def mapimage(coords, zoom=15,size=(TS,TS)):
- if len(coords) == 1:
- co = coords[0]
- filename = encode(co[0],co[1])+'.png'
- if path.isfile(filename):
- if path.getctime(filename) > time.time() - 60*60*24*2:
- return
+ def lattile(self, zoom):
+ rad = radians(self.latitude)
+ tile = (1-log(tan(rad)+1/cos(rad))/pi)/2*2**zoom
+ return tile
+
+ 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)
+
+ 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'
+# 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)
- img = []
+
+ 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)
-# print url
- 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)
- else:
- 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])
+
+ def db_xml(self):
+ 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,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,
+ 'accept-language': language}
+
+ 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
+
+ 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):
+ 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):
+ res = Geodesic.WGS84.Inverse(p1[0], p1[1], p2[0], p2[1])
+ return res['s12']
+
+def mark(image, coord):
+ draw = ImageDraw.Draw(image)
+ x, y = coord
+ r = 5
+ 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 = 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
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'])
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))