1 /*
2 * Copyright (C) 2010-2011 Dmitry Marakasov
3 *
4 * This file is part of glosm.
5 *
6 * glosm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * glosm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with glosm. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glosm/MercatorProjection.hh>
21 #include <glosm/PreloadedXmlDatasource.hh>
22 #include <glosm/GeometryGenerator.hh>
23 #include <glosm/GeometryLayer.hh>
24 #include <glosm/OrthoViewer.hh>
25 #include <glosm/geomath.h>
26
27 #include "PBuffer.hh"
28 #include "PixelBuffer.hh"
29 #include "PngWriter.hh"
30
31 #include <GL/glx.h>
32 #include <X11/Xlib.h>
33 #include <getopt.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38
39 #include <cstdio>
40
41 struct LevelInfo {
42 int tiling;
43 int flags;
44
operator !=LevelInfo45 bool operator!= (const LevelInfo& other) const {
46 return tiling != other.tiling || flags != other.flags;
47 }
48 };
49
50 static LevelInfo LevelInfos[] = {
51 { 0, GeometryDatasource::GROUND }, /* 0 */
52 { 1, GeometryDatasource::GROUND }, /* 1 */
53 { 2, GeometryDatasource::GROUND }, /* 2 */
54 { 3, GeometryDatasource::GROUND }, /* 3 */
55 { 4, GeometryDatasource::GROUND }, /* 4 */
56 { 5, GeometryDatasource::GROUND }, /* 5 */
57 { 6, GeometryDatasource::GROUND }, /* 6 */
58 { 7, GeometryDatasource::GROUND }, /* 7 */
59 { 8, GeometryDatasource::GROUND }, /* 8 */
60 { 9, GeometryDatasource::GROUND }, /* 9 */
61 { 10, GeometryDatasource::GROUND }, /* 10 */
62 { 11, GeometryDatasource::EVERYTHING }, /* 11 */
63 { 12, GeometryDatasource::EVERYTHING }, /* 12 */
64 { 12, GeometryDatasource::EVERYTHING }, /* 13 */
65 { 12, GeometryDatasource::EVERYTHING }, /* 14 */
66 { 12, GeometryDatasource::EVERYTHING }, /* 15 */
67 { 13, GeometryDatasource::EVERYTHING }, /* 16 */
68 { 13, GeometryDatasource::EVERYTHING }, /* 17 */
69 { 14, GeometryDatasource::EVERYTHING }, /* 18 */
70 };
71
usage(const char * progname)72 void usage(const char* progname) {
73 fprintf(stderr, "Usage: %s [-0123456789] [-s skew] [-z minzoom] [-Z maxzoom] -x minlon -X maxlon -y minlat -Y maxlat infile.osm outdir\n", progname);
74 exit(1);
75 }
76
RenderTiles(PBuffer & pbuffer,OrthoViewer & viewer,GeometryLayer & layer,const char * target,float minlon,float minlat,float maxlon,float maxlat,int minzoom,int maxzoom,int pnglevel)77 int RenderTiles(PBuffer& pbuffer, OrthoViewer& viewer, GeometryLayer& layer, const char* target, float minlon, float minlat, float maxlon, float maxlat, int minzoom, int maxzoom, int pnglevel) {
78 int x, y, zoom, ntiles = 0;
79 PixelBuffer pixels(256, 256, 3);
80
81 char path[FILENAME_MAX];
82 snprintf(path, sizeof(path), "%s", target);
83 mkdir(path, 0777);
84 for (zoom = minzoom; zoom <= maxzoom; zoom++) {
85 layer.SetLevel(LevelInfos[zoom].tiling);
86 layer.SetFlags(LevelInfos[zoom].flags);
87 if (zoom > 0 && LevelInfos[zoom-1] != LevelInfos[zoom])
88 layer.Clear();
89
90 int minxtile = (int)((minlon + 180.0)/360.0*powf(2.0, zoom));
91 int maxxtile = (int)((maxlon + 180.0)/360.0*powf(2.0, zoom));
92 int minytile = (int)((-mercator(maxlat/180.0*M_PI)/M_PI*180.0 + 180.0)/360.0*powf(2.0, zoom));
93 int maxytile = (int)((-mercator(minlat/180.0*M_PI)/M_PI*180.0 + 180.0)/360.0*powf(2.0, zoom));
94
95 snprintf(path, sizeof(path), "%s/%d", target, zoom);
96 mkdir(path, 0777);
97 for (x = minxtile; x <= maxxtile; ++x) {
98 snprintf(path, sizeof(path), "%s/%d/%d", target, zoom, x);
99 mkdir(path, 0777);
100 for (y = minytile; y <= maxytile; ++y) {
101 snprintf(path, sizeof(path), "%s/%d/%d/%d.png", target, zoom, x, y);
102
103 BBoxi bbox = BBoxi::ForMercatorTile(zoom, x, y);
104 viewer.SetBBox(bbox);
105
106 BBoxi request_bbox = bbox;
107 /* expand request 1km down for skewed buildings to show correctly
108 * that is, we assume maximum object height of 1km */
109
110 /* @todo take skew into account */
111 request_bbox.bottom -= 1000.0 / WGS84_EARTH_EQ_LENGTH * 360.0 * GEOM_UNITSINDEGREE;
112
113 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
114 layer.GarbageCollect();
115 layer.LoadArea(request_bbox, TileManager::SYNC);
116 layer.Render(viewer);
117 glFinish();
118
119 pbuffer.GetPixels(pixels, 0, 0);
120
121 PngWriter writer(path, 256, 256, pnglevel);
122 writer.WriteImage(pixels, 0, 0);
123
124 ntiles++;
125 }
126 }
127 }
128
129 return ntiles;
130 }
131
real_main(int argc,char ** argv)132 int real_main(int argc, char** argv) {
133 const char* progname = argv[0];
134
135 int pnglevel = 6;
136
137 float minlat = 0.0f, maxlat = 0.0f, minlon = 0.0f, maxlon = 0.0f;
138 int minzoom = 0, maxzoom = 18;
139
140 float skew = 1.0f;
141
142 int c;
143 while ((c = getopt(argc, argv, "0123456789s:z:Z:x:X:y:Y:")) != -1) {
144 switch (c) {
145 case '0': case '1': case '2': case '3': case '4':
146 case '5': case '6': case '7': case '8': case '9':
147 pnglevel = c - '0';
148 break;
149 case 's': skew = strtof(optarg, NULL); break;
150 case 'z': minzoom = strtol(optarg, NULL, 10); break;
151 case 'Z': maxzoom = strtol(optarg, NULL, 10); break;
152 case 'x': minlon = strtof(optarg, NULL); break;
153 case 'X': maxlon = strtof(optarg, NULL); break;
154 case 'y': minlat = strtof(optarg, NULL); break;
155 case 'Y': maxlat = strtof(optarg, NULL); break;
156 default:
157 usage(progname);
158 }
159 }
160
161 argc -= optind;
162 argv += optind;
163
164 if (minlon < -180.0f || maxlon > 180.0 || minlon > maxlon)
165 usage(progname);
166 if (minlat < -85.0f || maxlat > 85.0 || minlat > maxlat)
167 usage(progname);
168 if (minzoom < 0 || minzoom > maxzoom)
169 usage(progname);
170 if (skew <= 0.0)
171 usage(progname);
172 if (argc != 2)
173 usage(progname);
174
175 /* OpenGL init */
176 PBuffer pbuffer(256, 256, 4);
177 glClearColor(0.5, 0.5, 0.5, 0.0);
178
179 /* glosm init */
180 OrthoViewer viewer;
181 viewer.SetSkew(skew);
182 PreloadedXmlDatasource osm_datasource;
183
184 fprintf(stderr, "Loading OSM data...\n");
185 osm_datasource.Load(argv[0]);
186
187 fprintf(stderr, "Creating geometry...\n");
188 GeometryGenerator geometry_generator(osm_datasource);
189
190 GeometryLayer layer(MercatorProjection(), geometry_generator);
191 layer.SetSizeLimit(128*1024*1024);
192
193 /* Rendering */
194 fprintf(stderr, "Rendering...\n");
195
196 struct timeval begin, end;
197
198 gettimeofday(&begin, NULL);
199 int ntiles = RenderTiles(pbuffer, viewer, layer, argv[1], minlon, minlat, maxlon, maxlat, minzoom, maxzoom, pnglevel);
200 gettimeofday(&end, NULL);
201
202 float dt = (float)(end.tv_sec - begin.tv_sec) + (float)(end.tv_usec - begin.tv_usec)/1000000.0f;
203
204 fprintf(stderr, "%.2f seconds, %d tiles: %.2f tiles/sec\n", dt, ntiles, (float)ntiles/dt);
205
206 return 0;
207 }
208
main(int argc,char ** argv)209 int main(int argc, char** argv) {
210 try {
211 return real_main(argc, argv);
212 } catch (std::exception &e) {
213 fprintf(stderr, "Exception: %s\n", e.what());
214 } catch (...) {
215 fprintf(stderr, "Unknown exception\n");
216 }
217
218 return 1;
219 }
220