source: subversion/applications/utils/mod_tile/gen_tile.cpp @ 8646

Last change on this file since 8646 was 8430, checked in by jonb, 11 years ago

mod_tile: Remove the map_lock. If this causes corrupted map tiles then you need to upgrade to a newer version of Mapnik (or set NUM_THREADS to 1).

File size: 6.9 KB
Line 
1#include <mapnik/map.hpp>
2#include <mapnik/datasource_cache.hpp>
3#include <mapnik/agg_renderer.hpp>
4#include <mapnik/filter_factory.hpp>
5#include <mapnik/color_factory.hpp>
6#include <mapnik/image_util.hpp>
7#include <mapnik/load_map.hpp>
8#include <mapnik/image_util.hpp>
9
10#include <iostream>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <dirent.h>
14#include <unistd.h>
15#include <pthread.h>
16
17#include "gen_tile.h"
18#include "protocol.h"
19#include "render_config.h"
20#include "dir_utils.h"
21#include "store.h"
22
23using namespace mapnik;
24
25#define DEG_TO_RAD (M_PIl/180)
26#define RAD_TO_DEG (180/M_PIl)
27
28#ifdef METATILE
29#define RENDER_SIZE (256 * (METATILE + 1))
30#else
31#define RENDER_SIZE (512)
32#endif
33
34
35
36static const int minZoom = 0;
37static const int maxZoom = 18;
38
39// The map projection must match the one in the osm.xml file
40static projection prj("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over");
41
42static double minmax(double a, double b, double c)
43{
44#define MIN(x,y) ((x)<(y)?(x):(y))
45#define MAX(x,y) ((x)>(y)?(x):(y))
46    a = MAX(a,b);
47    a = MIN(a,c);
48    return a;
49}
50
51class GoogleProjection
52{
53    double *Ac, *Bc, *Cc, *zc;
54
55    public:
56        GoogleProjection(int levels=18) {
57            Ac = new double[levels];
58            Bc = new double[levels];
59            Cc = new double[levels];
60            zc = new double[levels];
61            int d, c = 256;
62            for (d=0; d<levels; d++) {
63                int e = c/2;
64                Bc[d] = c/360.0;
65                Cc[d] = c/(2 * M_PIl);
66                zc[d] = e;
67                Ac[d] = c;
68                c *=2;
69            }
70        }
71
72        void fromLLtoPixel(double &x, double &y, int zoom) {
73            double d = zc[zoom];
74            double f = minmax(sin(DEG_TO_RAD * y),-0.9999,0.9999);
75            x = round(d + x * Bc[zoom]);
76            y = round(d + 0.5*log((1+f)/(1-f))*-Cc[zoom]);
77        }
78        void fromPixelToLL(double &x, double &y, int zoom) {
79            double e = zc[zoom];
80            double g = (y - e)/-Cc[zoom];
81            x = (x - e)/Bc[zoom];
82            y = RAD_TO_DEG * ( 2 * atan(exp(g)) - 0.5 * M_PIl);
83        }
84};
85
86static void load_fonts(const char *font_dir, int recurse)
87{
88    DIR *fonts = opendir(font_dir);
89    struct dirent *entry;
90    char path[PATH_MAX]; // FIXME: Eats lots of stack space when recursive
91
92    if (!fonts) {
93        fprintf(stderr, "Unable to open font directory: %s\n", font_dir);
94        return;
95    }
96
97    while ((entry = readdir(fonts))) {
98        struct stat b;
99        char *p;
100
101        if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
102            continue;
103        snprintf(path, sizeof(path), "%s/%s", font_dir, entry->d_name);
104        if (stat(path, &b))
105            continue;
106        if (S_ISDIR(b.st_mode)) {
107            if (recurse)
108                load_fonts(path, recurse);
109            continue;
110        }
111        p = strrchr(path, '.');
112        if (p && !strcmp(p, ".ttf")) {
113            //fprintf(stderr, "Loading font: %s\n", path);
114            freetype_engine::register_font(path);
115        }
116    }
117    closedir(fonts);
118}
119
120static GoogleProjection gprj(maxZoom+1);
121
122#ifdef METATILE
123static enum protoCmd render(Map &m, int x, int y, int z, unsigned int size)
124{
125    int render_size = 256 * (size + 1);
126    double p0x = x * 256;
127    double p0y = (y + size) * 256;
128    double p1x = (x + size) * 256;
129    double p1y = y * 256;
130
131    //std::cout << "META TILE " << z << " " << x << "-" << x+size-1 << " " << y << "-" << y+size-1 << "\n";
132
133    gprj.fromPixelToLL(p0x, p0y, z);
134    gprj.fromPixelToLL(p1x, p1y, z);
135
136    prj.forward(p0x, p0y);
137    prj.forward(p1x, p1y);
138
139    Envelope<double> bbox(p0x, p0y, p1x,p1y);
140    bbox.height(bbox.height() * (size+1.0)/size);
141    bbox.width(bbox.width() * (size+1.0)/size);
142    m.resize(render_size, render_size);
143    m.zoomToBox(bbox);
144    //m.zoom(size+1);
145
146    Image32 buf(render_size, render_size);
147    agg_renderer<Image32> ren(m,buf);
148    ren.apply();
149
150
151    // Split the meta tile into an NxN grid of tiles
152    unsigned int xx, yy;
153    for (yy = 0; yy < size; yy++) {
154        for (xx = 0; xx < size; xx++) {
155            int yoff = 128 + yy * 256;
156            int xoff = 128 + xx * 256;
157            image_view<ImageData32> vw(xoff, yoff, 256, 256, buf.data());
158
159            char filename[PATH_MAX];
160            char tmp[PATH_MAX];
161            xyz_to_path(filename, sizeof(filename), x+xx, y+yy, z);
162            if (mkdirp(filename))
163                return cmdNotDone;
164            snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
165            //std::cout << "Render " << z << " " << x << "(" << xx << ") " << y << "(" << yy << ") " << filename << "\n";
166            save_to_file(vw, tmp,"png256");
167            if (rename(tmp, filename)) {
168                perror(tmp);
169                return cmdNotDone;
170            }
171        }
172    }
173    std::cout << "DONE TILE " << z << " " << x << "-" << x+size-1 << " " << y << "-" << y+size-1 << "\n";
174    return cmdDone; // OK
175}
176#else
177static enum protoCmd render(Map &m, int x, int y, int z)
178{
179    char filename[PATH_MAX];
180    char tmp[PATH_MAX];
181    double p0x = x * 256.0;
182    double p0y = (y + 1) * 256.0;
183    double p1x = (x + 1) * 256.0;
184    double p1y = y * 256.0;
185
186    gprj.fromPixelToLL(p0x, p0y, z);
187    gprj.fromPixelToLL(p1x, p1y, z);
188
189    prj.forward(p0x, p0y);
190    prj.forward(p1x, p1y);
191
192    Envelope<double> bbox(p0x, p0y, p1x,p1y);
193    bbox.width(bbox.width() * 2);
194    bbox.height(bbox.height() * 2);
195    m.zoomToBox(bbox);
196
197    Image32 buf(RENDER_SIZE, RENDER_SIZE);
198    agg_renderer<Image32> ren(m,buf);
199    ren.apply();
200
201    xyz_to_path(filename, sizeof(filename), x, y, z);
202    if (mkdirp(filename))
203        return cmdNotDone;
204    snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
205
206    image_view<ImageData32> vw(128,128,256,256, buf.data());
207    //std::cout << "Render " << z << " " << x << " " << y << " " << filename << "\n";
208    save_to_file(vw, tmp,"png256");
209    if (rename(tmp, filename)) {
210        perror(tmp);
211        return cmdNotDone;
212    }
213
214    return cmdDone; // OK
215}
216#endif
217
218
219void render_init(void)
220{
221    // TODO: Make these module options
222    datasource_cache::instance()->register_datasources(MAPNIK_PLUGINS);
223    load_fonts(FONT_DIR, FONT_RECURSE);
224}
225
226
227void *render_thread(__attribute__((unused)) void *unused)
228{
229    Map m(RENDER_SIZE, RENDER_SIZE);
230
231    load_map(m,OSM_XML);
232
233    while (1) {
234        enum protoCmd ret;
235        struct item *item = fetch_request();
236        if (item) {
237            struct protocol *req = &item->req;
238#ifdef METATILE
239            // At very low zoom the whole world may be smaller than METATILE
240            unsigned int size = MIN(METATILE, 1 << req->z);
241            ret = render(m, item->mx, item->my, req->z, size);
242            if (ret == cmdDone)
243                process_meta(item->mx, item->my, req->z);
244#else
245            ret = render(m, req->x, req->y, req->z);
246#endif
247            send_response(item, ret);
248        } else
249            sleep(1); // TODO: Use an event to indicate there are new requests
250    }
251    return NULL;
252}
Note: See TracBrowser for help on using the repository browser.