text_plain_output_1.png
import math

class Panorama:
    """Class that represents a picture returned by Google Street View Static API"""
    def __init__(self, width=640, height=640, fov=120, heading=0, pitch=0):
        self.width = width
        self.height = height
        self.fov = fov
        self.heading = heading
        self.pitch = pitch
    def unmap(self, heading, pitch):
        """Returns the pixel coordinates corresponding to the given heading and pitch offsets"""
        fov = self.fov * math.pi / 180.0
        width = self.width
        height = self.height
        f = 0.5 * width / math.tan(0.5 * fov)
        h = heading * math.pi / 180.0
        p = pitch * math.pi / 180.0
        x = f * math.cos(p) * math.sin(h)
        y = f * math.cos(p) * math.cos(h)
        z = f * math.sin(p)
        h0 = self.heading * math.pi / 180.0
        p0 = self.pitch * math.pi / 180.0
        x0 = f * math.cos(p0) * math.sin(h0)
        y0 = f * math.cos(p0) * math.cos(h0)
        z0 = f * math.sin(p0)
        t = f * f / (x0 * x + y0 * y + z0 * z)
        ux = math.copysign(math.cos(h0), math.cos(p0))
        uy = -math.copysign(math.sin(h0), math.cos(p0))
        uz = 0
        vx = -math.sin(p0) * math.sin(h0)
        vy = -math.sin(p0) * math.cos(h0)
        vz = math.cos(p0)
        x1 = t * x
        y1 = t * y
        z1 = t * z
        dx10 = x1 - x0
        dy10 = y1 - y0
        dz10 = z1 - z0
        du = ux * dx10 + uy * dy10 + uz * dz10
        dv = vx * dx10 + vy * dy10 + vz * dz10
        return (du + width / 2, height / 2 - dv)
    def map(self, u, v):
        """Returns a (heading, pitch) tuple corresponding to the given (x, y) offset in pixels"""
        fov = self.fov * math.pi / 180.0
        width = self.width
        height = self.height
        h0 = self.heading * math.pi / 180.0
        p0 = self.pitch * math.pi / 180.0
        f = 0.5 * width / math.tan(0.5 * fov)
        x0 = f * math.cos(p0) * math.sin(h0)
        y0 = f * math.cos(p0) * math.cos(h0)
        z0 = f * math.sin(p0)
        du = u - width / 2
        dv = height / 2 - v
        ux = math.copysign(math.cos(h0), math.cos(p0))
        uy = -math.copysign(math.sin(h0), math.cos(p0))
        uz = 0
        vx = -math.sin(p0) * math.sin(h0)
        vy = -math.sin(p0) * math.cos(h0)
        vz = math.cos(p0)
        x = x0 + du * ux + dv * vx
        y = y0 + du * uy + dv * vy
        z = z0 + du * uz + dv * vz
        R = math.sqrt(x * x + y * y + z * z)
        h = math.atan2(x, y)
        p = math.asin(z / R)
        return (h * 180.0 / math.pi, p * 180.0 / math.pi)

p = Panorama()
print(p.unmap(-17, 16))
print(p.map(264, 264))
print(p.unmap(-57, 40))
print(p.map(40, 40))