source: subversion/applications/rendering/toposm/coords.py @ 27489

Last change on this file since 27489 was 25435, checked in by ahlzen, 9 years ago

Minor refactoring and cleanup of the TopOSM code.

File size: 5.4 KB
Line 
1#!/usr/bin/python
2
3"""coords.py: Coordinate transformation functions for TopOSM"""
4
5from math import pi, cos, sin, log, exp, atan, ceil, floor
6import mapnik;
7from env import *;
8
9__author__      = "Lars Ahlzen"
10__copyright__   = "(c) Lars Ahlzen 2008-2011"
11__license__     = "GPLv2"
12
13
14# NOTE: In pixel and tile coordinates, the Y-coordinate
15# increases towards the south, which is opposite the standard
16# notation for latitudes.
17
18# NOTE: Lon/Lat coordinates are assumed to be given in WGS84 unless
19# otherwise specified.
20
21
22DEG_TO_RAD = pi/180
23RAD_TO_DEG = 180/pi
24
25def minmax (a,b,c):
26    a = max(a,b)
27    a = min(a,c)
28    return a
29
30# Based on code from generate_tiles.py
31class GoogleProjection:   
32    def __init__(self, levels=22):
33        self.Bc = []
34        self.Cc = []
35        self.zc = []
36        self.Ac = []
37        c = 256
38        for d in range(0, levels):
39            e = c / 2;
40            self.Bc.append(c / 360.0)
41            self.Cc.append(c / (2 * pi))
42            self.zc.append((e, e))
43            self.Ac.append(c)
44            c *= 2
45               
46    def LLToPixel(self, coord, zoom):
47         d = self.zc[zoom]
48         e = round(d[0] + coord.x * self.Bc[zoom])
49         f = minmax(sin(DEG_TO_RAD * coord.y), -0.9999, 0.9999)
50         g = round(d[1] + 0.5*log((1+f)/(1-f)) * -self.Cc[zoom])
51         return mapnik.Coord(e, g)
52     
53    def pixelToLL(self, coord, zoom):
54         e = self.zc[zoom]
55         f = (coord.x - e[0]) / self.Bc[zoom]
56         g = (coord.y - e[1]) / -self.Cc[zoom]
57         h = RAD_TO_DEG * (2 * atan(exp(g)) - 0.5 * pi)
58         return mapnik.Coord(f, h)
59   
60    def envLLToPixel(self, env, zoom):
61        lb = self.LLToPixel(mapnik.Coord(env.minx, env.miny), zoom)
62        rt = self.LLToPixel(mapnik.Coord(env.maxx, env.maxy), zoom)
63        return mapnik.Envelope(lb.x, lb.y, rt.x, rt.y)
64
65    def envPixelToLL(self, env, zoom):
66        lb = self.pixelToLL(mapnik.Coord(env.minx, env.miny), zoom)
67        rt = self.pixelToLL(mapnik.Coord(env.maxx, env.maxy), zoom)
68        return mapnik.Envelope(lb.x, lb.y, rt.x, rt.y)
69
70
71GOOGLE_PROJECTION = GoogleProjection()
72LATLONG_PROJECTION = mapnik.Projection(LATLONG_PROJECTION_DEF)
73MERCATOR_PROJECTION = mapnik.Projection(MERCATOR_PROJECTION_DEF)
74
75
76##### Geographic coordinate transformation
77
78def LLToMerc(coord):
79    """Converts a Coord(lon,lat) or Envelope(l,b,r,t) to
80    OSM Mercator (x,y)."""
81    return MERCATOR_PROJECTION.forward(coord)
82
83def mercToLL(coord):
84    """Converts an OSM Mercator Coord(x,y) or Envelope(l,b,r,t)
85    to (lon,lat)."""
86    return MERCATOR_PROJECTION.inverse(coord)
87
88def LLToPixel(coord, z):
89    """Converts a Coord(lon,lat) or Envelope(l,b,r,t) to
90    OSM (x,y) pixel coordinates at the specified zoom level."""
91    if isinstance(coord, mapnik.Coord):
92        return GOOGLE_PROJECTION.LLToPixel(coord, z)
93    else:
94        return GOOGLE_PROJECTION.envLLToPixel(coord, z)
95
96def pixelToLL(coord, z):
97    """Converts an OSM pixel Coord(x,y) or Envelope(l,b,r,t)
98    to (lon,lat) at the specified zoom level."""
99    if isinstance(coord, mapnik.Coord):
100        return GOOGLE_PROJECTION.pixelToLL(coord, z)
101    else:
102        return GOOGLE_PROJECTION.envPixelToLL(coord, z)
103
104def pixelToMerc(coord, z):
105    """Converts an OSM pixel Coord(x,y) or Envelope(l,b,r,t)
106    to OSM Mercator (x,y) at the specified zoom level."""
107    # No direct transformation. Use px->ll->merc.
108    if isinstance(coord, mapnik.Coord):
109        ll = GOOGLE_PROJECTION.pixelToLL(coord, z)
110    else:
111        ll = GOOGLE_PROJECTION.envPixelToLL(coord, z)
112    return MERCATOR_PROJECTION.forward(ll)
113
114def mercToPixel(coord, z):
115    """Converts an OSM Mercator Coord(x,y) or Envelope(l,b,r,t)
116    to OSM pixel coordinates (x,y) at the specified zoom level."""
117    # No direct transformation. Use merc->ll->pixel.
118    ll = MERCATOR_PROJECTION.inverse(coord)
119    if isinstance(coord, mapnik.Coord):
120        return GOOGLE_PROJECTION.LLToPixel(ll, z)
121    else:
122        return GOOGLE_PROJECTION.envLLToPixel(ll, z)
123
124
125##### Tile coordinates
126
127def getPixelTileEnv(x, y, ntiles = 1, includeBorder = True):
128    """Returns the OSM Pixel coordinate Envelope for the tile(s) for
129    the specified tile(s)."""
130    border = 0
131    size = TILE_SIZE * ntiles
132    if includeBorder:
133        border = BORDER_WIDTH
134    return mapnik.Envelope(
135        x * size - border,
136        y * size - border,
137        (x+1) * size + border,
138        (y+1) * size + border)
139
140def getLLTileEnv(z, x, y, ntiles = 1, includeBorder = True):
141    """Returns the lon/lat Envelope for the tile(s) at the specified
142    tile coordinates."""
143    return pixelToLL(getPixelTileEnv(x, y, ntiles, includeBorder), z)
144
145def getMercTileEnv(z, x, y, ntiles = 1, includeBorder = True):
146    """Returns the OSM Mercator Envelope for the tile(s) at the specified
147    tile coordinates."""
148    return pixelToMerc(getPixelTileEnv(x, y, ntiles, includeBorder), z)
149
150def getTileAtLL(coord, z, ntiles = 1):
151    """Returns the OSM tile coordinates (x, y) at the specified
152    Coord(lon,lat) and zoom level."""
153    px = LLToPixel(coord, z)
154    size = TILE_SIZE * ntiles
155    return ((int)(px.x / size), (int)(px.y / size))
156
157def getTileRange(envLL, z, ntiles = 1):
158    """Returns the tile number range (fromx, tox, fromy, toy)
159    that covers the envelope at the specified zoom level."""
160    topleft = mapnik.Coord(envLL.minx, envLL.maxy)
161    bottomright = mapnik.Coord(envLL.maxx, envLL.miny)
162    tltile = getTileAtLL(topleft, z, ntiles)
163    brtile = getTileAtLL(bottomright, z, ntiles)
164    return (tltile[0], brtile[0], tltile[1], brtile[1])
165
Note: See TracBrowser for help on using the repository browser.