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

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

Applied MacOSX compile fixes from Artem with a few modifications

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