#!/usr/bin/python
from math import pi,cos,sin,log,exp,atan

DEG_TO_RAD = pi/180
RAD_TO_DEG = 180/pi

def minmax (a,b,c):
    a = max(a,b)
    a = min(a,c)
    return a

class GoogleProjection:
    def __init__(self,levels=18):
        self.Bc = []
        self.Cc = []
        self.zc = []
        self.Ac = []
        c = 256
        for d in range(0,levels):
            e = c/2;
            self.Bc.append(c/360.0)
            self.Cc.append(c/(2 * pi))
            self.zc.append((e,e))
            self.Ac.append(c)
            c *= 2
                
    def fromLLtoPixel(self,ll,zoom):
         d = self.zc[zoom]
         e = round(d[0] + ll[0] * self.Bc[zoom])
         f = minmax(sin(DEG_TO_RAD * ll[1]),-0.9999,0.9999)
         g = round(d[1] + 0.5*log((1+f)/(1-f))*-self.Cc[zoom])
         return (e,g)
     
    def fromPixelToLL(self,px,zoom):
         e = self.zc[zoom]
         f = (px[0] - e[0])/self.Bc[zoom]
         g = (px[1] - e[1])/-self.Cc[zoom]
         h = RAD_TO_DEG * ( 2 * atan(exp(g)) - 0.5 * pi)
         return (f,h)

def get(ll, z):
    print "get(",ll, z,")"

    gprj = GoogleProjection(z+1)
    px0 = gprj.fromLLtoPixel(ll,z)
    tx0 = int(px0[0]/256.0)
    ty0 = int(px0[1]/256.0)
    print "Tile: z(",z,") x(",tx0,") y(",ty0,"), offset(", px0[0] - tx0 * 256.0, ",", px0[1] - ty0 * 256.0,")"

if __name__ == "__main__":
    print "BAD"
    get((60.3434, 5.2834), 15)
    print "Good"
    get((5.2834, 60.3434), 15)

