├── .gitignore ├── Jamroot ├── Makefile ├── README.md ├── binding.gyp ├── docs └── opensciencemap-format.md ├── lib ├── index.js └── vector_server.js ├── osm_vectors.xml ├── package.json ├── pbf_test.py ├── proto └── TileData.proto ├── server.js ├── src ├── main.cpp ├── opensciencemap_backend.hpp ├── opensciencemap_backend_pbf.hpp ├── tags.cpp ├── tags.hpp ├── vector_renderer.cpp ├── vector_renderer.hpp ├── vector_renderer_impl.hpp └── vector_server.cpp ├── test ├── check.sh └── load.sh ├── tiles ├── 10842.osmtile ├── 43373.osmtile ├── 5430.osmtile └── test.osmtile ├── vector_tile.py ├── www └── index.html └── zoom_scales.xml.inc /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | build 16 | node_modules -------------------------------------------------------------------------------- /Jamroot: -------------------------------------------------------------------------------- 1 | ############################ Boost.Build.v2 ############################################# 2 | 3 | local MAPNIK_DIR = "/opt/mapnik" ; 4 | local MAPNIK_DEPS_DIR = "/opt/mapnik_deps" ; 5 | local BOOST_DIR = "/opt/boost" ; 6 | 7 | 8 | lib mapnik : : mapnik $(MAPNIK_DIR)/lib ; 9 | lib program_options : : boost_program_options $(BOOST_DIR)/lib ; 10 | lib system : : boost_system $(BOOST_DIR)/lib ; 11 | lib regex : : boost_regex $(BOOST_DIR)/lib ; 12 | lib sqlite3 : : sqlite3 $(MAPNIK_DIR)/lib ; 13 | lib icuuc : : icuuc $(MAPNIK_DEPS_DIR)/lib ; 14 | lib protobuf : : protobuf $(MAPNIK_DEPS_DIR)/lib ; 15 | 16 | exe vector-tile-server 17 | : 18 | ./src/main.cpp 19 | ./src/vector_renderer.cpp 20 | ./src/tags.cpp 21 | ./src/TileData.pb.cc 22 | .//mapnik 23 | .//icuuc 24 | .//program_options 25 | .//regex 26 | .//system 27 | .//protobuf 28 | : 29 | $(BOOST_DIR)/include 30 | $(MAPNIK_DIR)/include 31 | $(MAPNIK_DIR)/include/mapnik/agg 32 | $(MAPNIK_DEPS_DIR)/include 33 | $(MAPNIK_DEPS_DIR)/include/freetype2 34 | -DMAPNIK_THREADSAFE 35 | -DMAPNIK_LOG 36 | -DMAPNIK_DEFAULT_LOG_SEVERITY=2 37 | ; 38 | 39 | ######################################################################################## -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #http://www.gnu.org/prep/standards/html_node/Standard-Targets.html#Standard-Targets 2 | 3 | all: server 4 | 5 | OS:=$(shell uname -s) 6 | 7 | server: 8 | @npm install 9 | 10 | clean: 11 | @rm -rf ./build 12 | @rm -rf ./node_modules/mapnik 13 | 14 | distclean: clean 15 | @rm -rf ./node_modules/ 16 | 17 | rebuild: clean server 18 | 19 | 20 | .PHONY: clean rebuild 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vector-tile-server 2 | ================== 3 | 4 | Vector tile server and rendering backend for Mapnik 5 | 6 | 7 | ## Dependencies 8 | 9 | * mapnik 10 | * node-mapnik 11 | * google-protobuf 12 | 13 | 14 | ## Building 15 | 16 | 1) Get mapnik master from github, at least https://github.com/mapnik/mapnik/commit/7ded35ef94a792ff2313e2087a5684c938fc1497 17 | 18 | 3) Build mapnik and install protobuf 19 | 20 | Install Mapnik like: 21 | 22 | git clone git://github.com/mapnik/mapnik.git 23 | cd mapnik && ./configure && make && make install 24 | 25 | On ubuntu get protobuf: 26 | 27 | sudo apt-get install libprotobuf7 libprotobuf-dev protobuf-compiler 28 | 29 | 2) Then within this directory do: 30 | 31 | protoc -Iproto/ --cpp_out=src/ proto/TileData.proto 32 | npm install 33 | 34 | 35 | If you get an error like `cannot run in wd` then try: 36 | 37 | npm install node-gyp -g 38 | node-gyp configure build 39 | 40 | ### Debug version 41 | 42 | To build a debug version do: 43 | 44 | node-gyp configure build -v -d 45 | 46 | Then edit the file `lib/vector_server.js` so that the Debug modules is used. 47 | 48 | 49 | ## Running server 50 | 51 | ```bash 52 | export LD_PRELOAD=./node_modules/mapnik/lib/_mapnik.node 53 | node ./server.js osm_vectors.xml 8000 54 | ``` 55 | 56 | 57 | ## Troubleshooting 58 | 59 | ### symbol conflicts 60 | 61 | If you hit an error like: 62 | 63 | ``` 64 | libprotobuf ERROR google/protobuf/descriptor_database.cc:109] Symbol name "google.protobuf.span" conflicts with the existing symbol "google.protobuf.span". 65 | libprotobuf FATAL google/protobuf/descriptor.cc:862] CHECK failed: generated_database_->Add(encoded_file_descriptor, size): 66 | ``` 67 | 68 | This indicates that libprotobuf has been linked twice. See: 69 | 70 | - http://code.google.com/p/protobuf/issues/detail?id=128 71 | - http://code.google.com/p/protobuf/issues/detail?id=370 72 | 73 | A crash like below may also indicate this problem: 74 | 75 | ``` 76 | Thread 2 Crashed: 77 | 0 libsystem_kernel.dylib 0x00007fff8926ece2 __pthread_kill + 10 78 | 1 libsystem_c.dylib 0x00007fff86f9a7d2 pthread_kill + 95 79 | 2 libsystem_c.dylib 0x00007fff86f8ba7a abort + 143 80 | 3 libsystem_c.dylib 0x00007fff86fea84c free + 389 81 | 4 libprotobuf.7.dylib 0x0000000105ea3d19 google::protobuf::RepeatedField::Add(unsigned int const&) + 33 82 | 5 node_vector_server.node 0x000000010d1ac90b mapnik::opensciencemap_backend_pbf::output_vector_tile() + 857 (opensciencemap_backend_pbf.hpp:238) 83 | 6 node_vector_server.node 0x000000010d1ac240 async_render(uv_work_s*) + 273 (vector_server.cpp:103) 84 | ``` 85 | 86 | ### symbols not found 87 | 88 | You will notice if you try to require just the vector_server 89 | node module you will get an odd symbol error: 90 | 91 | ```sh 92 | $ node 93 | > require('./lib/vector_server'); 94 | Error: dlopen(/Users/dane/projects/vector-tile-server/build/Release/node_vector_server.node, 1): Symbol not found: __ZN3Map11constructorE 95 | Referenced from: /Users/dane/projects/vector-tile-server/build/Release/node_vector_server.node 96 | Expected in: dynamic lookup 97 | 98 | at Object.Module._extensions..node (module.js:485:11) 99 | at Module.load (module.js:356:32) 100 | at Function.Module._load (module.js:312:12) 101 | at Module.require (module.js:362:17) 102 | at require (module.js:378:17) 103 | at Object. (/Users/dane/projects/vector-tile-server/lib/vector_server.js:1:103) 104 | at Module._compile (module.js:449:26) 105 | at Object.Module._extensions..js (module.js:467:10) 106 | at Module.load (module.js:356:32) 107 | at Function.Module._load (module.js:312:12) 108 | ``` 109 | 110 | The reason for this is that the node-mapnik module symbols need to be available for 111 | the `node_vector_server.node` code to initialize properly. So, to solve this make sure 112 | to first require node-mapnik. This works: 113 | 114 | ``` 115 | $ node 116 | > var mapnik = require('mapnik') 117 | undefined 118 | > require('./lib/vector_server'); 119 | { render: [Function] } 120 | ``` 121 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'target_defaults': { 3 | 'default_configuration': 'Release', 4 | 'configurations': { 5 | 'Debug': { 6 | 'cflags_cc!': ['-O3', '-DNDEBUG'], 7 | 'xcode_settings': { 8 | 'OTHER_CPLUSPLUSFLAGS!':['-O3', '-DNDEBUG'] 9 | } 10 | }, 11 | 'Release': { 12 | # nothing needed, use defaults 13 | } 14 | }, 15 | 'include_dirs': [ 16 | 'node_modules/mapnik/src', 17 | ], 18 | 'conditions': [ 19 | ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or OS=="mac"', { 20 | 'cflags_cc!': ['-fno-rtti', '-fno-exceptions'], 21 | 'cflags_cc' : ['= TAGS_MAX : 60 | tagNum -= TAGS_LIMIT # custom tags encoding 61 | ``` 62 | |----------------------------- 63 | 64 | 65 | |----------------------------- 66 | | 67 | | TAG_ELEM_INDICES = 1 68 | |----------------------------- 69 | | indexCount : Varint32 70 | |----------------------------- 71 | 72 | |----------------------------- 73 | | TAG_ELEM_INDEX = 12 74 | |----------------------------- 75 | | 76 | | Array of Varint32 77 | | size = indexCount 78 | | 79 | |----------------------------- 80 | 81 | |----------------------------- 82 | | TAG_ELEM_COORD = 13 83 | |----------------------------- 84 | | 85 | | 0..N Varin32 X/Y pairs encoded 86 | | using ZigZag algorithm 87 | | 88 | |----------------------------- 89 | 90 | |----------------------------- 91 | | TAG_ELEM_LAYER = 21 92 | |----------------------------- 93 | | 94 | | ?? 95 | |----------------------------- 96 | 97 | 98 | * - Varint32 encoding 99 | 100 | ** - ZigZag encoding 101 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./vector_server'); 2 | -------------------------------------------------------------------------------- /lib/vector_server.js: -------------------------------------------------------------------------------- 1 | var server = module.exports = exports = require('../build/Release/node_vector_server.node'); 2 | -------------------------------------------------------------------------------- /osm_vectors.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | %entities; 5 | ]> 6 | 7 | 8 | 9 | 10 | osm 11 | -20037508.34 -20037508.34 20037508.34 20037508.34 12 | way 13 | postgis 14 | 200 15 | 16 | 17 | 23 | 24 | 25 | 31 | 32 | 39 | 40 | 46 | 47 | 55 | 56 | 58 | polygon 59 | 60 | (select * from planet_osm_polygon where osm_id > 0) as osm_polygon 61 | 62 | 63 | 64 | 67 | line 68 | 69 | (select * from planet_osm_line where osm_id > 0) as osm_line 70 | 71 | 72 | 73 | 76 | roads 77 | 78 | (select name,highway,oneway,ref,way from planet_osm_roads where osm_id > 0 and highway='motorway') as roads 79 | 80 | 81 | 82 | 85 | point 86 | 87 | (select * from planet_osm_point where osm_id > 0) as points 88 | 89 | 90 | 91 | 92 | 95 | city 96 | 97 | (select * from planet_osm_point where osm_id > 0 and place='city') as city 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "node-vector-server", 3 | "description" : "Vector backend for mapnik", 4 | "url" : "http://github.com/mapnik/vector-tile-server", 5 | "homepage" : "http://mapnik.org", 6 | "author" : "Artem Pavlenko (mapnik.org)", 7 | "version" : "0.0.1a", 8 | "main" : "./lib/vector_renderer.js", 9 | "bugs" : { 10 | "email" : "artem@mapnik.org", 11 | "url" : "fixme" 12 | }, 13 | "keywords" : [ 14 | "map", 15 | "graphics", 16 | "canvas", 17 | "tile", 18 | "mapnik", 19 | "carto" 20 | ], 21 | "repository" : { 22 | "type" : "git", 23 | "url" : "fixme" 24 | }, 25 | "contributors" : ["Artem Pavlenko"], 26 | "licenses" : [ 27 | { 28 | "type": "LGPLv2", 29 | "url": "FIXME" 30 | } 31 | ], 32 | "dependencies" : { 33 | "generic-pool": "~2.0.0", 34 | "mapnik" : "~0.7.22", 35 | "sphericalmercator": "~1.0.2", 36 | "eio" : "~0.1.0", 37 | "mkdirp" : "~0.3.5", 38 | "mime" : "*" 39 | }, 40 | "devDependencies": { 41 | "mocha": "*", 42 | "jshint" : "~0.5.x" 43 | }, 44 | 45 | "directories" : { 46 | "src": "src" 47 | }, 48 | "engines" : { 49 | "node": ">= 0.6.13 && < 0.9.0" 50 | }, 51 | "scripts" : { 52 | "install" : "node-gyp -v configure build", 53 | "test" : "mocha -R spec" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pbf_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # protoc --python_out=. proto/TileData.proto 5 | # 6 | 7 | import sys 8 | import proto.TileData_pb2 9 | 10 | if __name__ == "__main__" : 11 | if len(sys.argv) != 2 : 12 | print>>sys.stderr, "Usage:", sys.argv[0], "" 13 | sys.exit(1) 14 | 15 | tile = proto.TileData_pb2.Data() 16 | 17 | try: 18 | f = open(sys.argv[1], "rb") 19 | tile.ParseFromString(f.read()[4:]) 20 | f.close() 21 | except IOError: 22 | print sys.argv[1] + ": Could not open file. Creating a new one." 23 | 24 | print tile 25 | -------------------------------------------------------------------------------- /proto/TileData.proto: -------------------------------------------------------------------------------- 1 | // Protocol Version 2 2 | 3 | package org.oscim.database.oscimap; 4 | 5 | //option java_package = "org.oscimap.database.pbmap"; 6 | option optimize_for = LITE_RUNTIME; 7 | 8 | message Data { 9 | message Element { 10 | optional uint32 num_indices = 1 [default = 1]; 11 | repeated uint32 tags = 11 [packed = true]; 12 | // minimum is 1, number of coordinates for each geometry 13 | repeated uint32 indices = 12 [packed = true]; 14 | repeated sint32 coordinates = 13 [packed = true]; 15 | optional uint32 layer = 21; 16 | // inteded for symbol and label placement, not used 17 | optional uint32 priority = 31; 18 | } 19 | // tags 20 | required uint32 num_tags = 1; 21 | repeated uint32 keys = 2 [packed = true]; 22 | repeated string values = 3; 23 | 24 | // non-closed linestring 25 | repeated Element lines = 11; 26 | 27 | // polygons are implicitly closed 28 | repeated Element polygons = 12; 29 | 30 | // POIs 31 | repeated Element points = 13; 32 | 33 | // prepared label placement, not used 34 | repeated Element waylabel = 21; 35 | 36 | // tile is completely water, not used 37 | optional uint32 water = 31; 38 | } 39 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // vector tile server 4 | 5 | var fs = require('fs'); // todo : remove 6 | var mapnik = require('mapnik'); 7 | var mercator = new(require('sphericalmercator')); 8 | var pool = require('generic-pool').Pool; 9 | var http = require('http'); 10 | var url = require("url"); 11 | var vector_ren = require('./lib/vector_server'); 12 | var eio = require('eio'); 13 | var path = require('path'); 14 | var exists = require('fs').exists || require('path').exists; 15 | var mime = require('mime'); 16 | var mkdirp = require('mkdirp'); 17 | 18 | // Increase number of threads to 1.5x the number of logical CPUs. 19 | var threads = Math.ceil(Math.max(4, require('os').cpus().length * 1.5)); 20 | eio.setMinParallel(threads); 21 | 22 | 23 | // should we default to chunked encoding? 24 | var chunked = false; 25 | 26 | // should osmtiles be cached on demand? 27 | var cache = false; 28 | 29 | // should we print client details? 30 | var debug = false; 31 | 32 | 33 | var root = "./www"; 34 | var port = '8000'; 35 | var stylesheet = 'osm_vectors.xml'; 36 | 37 | var usage = 'usage: node server.js [stylesheet] [port] [root]'; 38 | usage += '\n default stylesheet: ' + stylesheet; 39 | usage += '\n default port: ' + port; 40 | usage += '\n default root directory: ' + root; 41 | 42 | if (process.argv.indexOf('-h') > -1 || process.argv.indexOf('--help') > -1) { 43 | console.log(usage); 44 | process.exit(0); 45 | } 46 | 47 | if (process.argv[2]) { 48 | stylesheet = process.argv[2]; 49 | } 50 | 51 | if (process.argv[3]) { 52 | port = process.argv[3]; 53 | } 54 | 55 | if (process.argv[4]) { 56 | root = process.argv[4]; 57 | } 58 | 59 | var map_pool = pool({ 60 | create: function(callback) { 61 | var obj = new mapnik.Map(256, 256); 62 | var opts = { strict: false }; 63 | try { 64 | obj.loadSync(stylesheet, opts); 65 | return callback(null,obj); 66 | } catch (err) { 67 | return callback(err); 68 | } 69 | /* 70 | // async loading will trigger when calling Mapnik's datasource_cache::create 71 | // if multiple tiles are accessed at the same time at first load 72 | // TODO - is this a bug in Mapnik singleton impl? 73 | obj.load(stylesheet, opts, function(err,obj) { 74 | if (err) return callback(err); 75 | return callback(null,obj); 76 | }); 77 | */ 78 | }, 79 | destroy: function(obj) { 80 | delete obj; 81 | }, 82 | max: threads 83 | }); 84 | 85 | var parse_url = function(uri, callback) { 86 | var matches = uri.match(/(\d+)/g); 87 | if (matches && matches.length == 3) { 88 | var format = path.extname(uri); 89 | if (!format || !(format.indexOf('png') > -1 || format == '.osmtile')) { 90 | var msg = "Invalid format, only 'png' and 'osmtile' are supported"; 91 | msg += ' (expected a url like /0/0/0.png or /0/0/0.osmtile'; 92 | msg += ' but got: ' + req.url + ')'; 93 | return callback(new Error(msg)); 94 | } 95 | try { 96 | var x = parseInt(matches[1], 10); 97 | var y = parseInt(matches[2], 10); 98 | var z = parseInt(matches[0], 10); 99 | return callback(null, 100 | { z: z, 101 | x: x, 102 | y: y, 103 | format: format.slice(1) 104 | }); 105 | } catch (err) { 106 | return callback(err, null); 107 | } 108 | } 109 | return callback(new Error('not a tile'),null); 110 | } 111 | 112 | var error = function(res,msg) { 113 | res.writeHead(500, { 114 | 'Content-Type': 'text/plain' 115 | }); 116 | return res.end(msg); 117 | } 118 | 119 | var renderer = function(map, params, res, filepath, cache) { 120 | var bbox = mercator.bbox(params.x, params.y, params.z, false, '900913'); 121 | map.extent = bbox; 122 | if (params.format == 'osmtile') { 123 | vector_ren.render(map, function(err, output) { 124 | process.nextTick(function() { 125 | map_pool.release(map); 126 | }); 127 | if (err) { 128 | console.log(err); 129 | return error(res,err.message) 130 | } 131 | console.log("TILE(%d/%d/%d) OUTPUT len=%d", params.z, params.x, params.y, output.length); 132 | osmtile_response(res,output); 133 | if (cache) { 134 | var dirname = path.dirname(filepath); 135 | mkdirp(dirname, function (err) { 136 | if (err) { 137 | console.log(err); 138 | return error(res,err.message) 139 | } 140 | fs.writeFile(filepath,output,function(err) { 141 | if (err) { 142 | console.log(err); 143 | return error(res,err.message) 144 | } 145 | return res.end(output); 146 | }); 147 | }); 148 | } else { 149 | return res.end(output); 150 | } 151 | }); 152 | } else { 153 | var im = new mapnik.Image(map.width,map.height); 154 | map.render(im,function(err,im) { 155 | process.nextTick(function() { 156 | map_pool.release(map); 157 | }); 158 | if (err) { 159 | console.log(err); 160 | return error(res,err.message) 161 | } 162 | im.encode(params.format,function(err,buffer) { 163 | if (err) { 164 | console.log(err); 165 | return error(res,err.message) 166 | } 167 | res.writeHead(200, {'Content-Type': 'image/png'}); 168 | if (!chunked) { 169 | res.writeHead(200,{'Content-length': buffer.length}); 170 | res.useChunkedEncodingByDefault=false; 171 | res.chunkedEncoding=false; 172 | } 173 | return res.end(buffer); 174 | }); 175 | }); 176 | } 177 | }; 178 | 179 | function osmtile_response(res,output) { 180 | var content_length = output.length + 4; 181 | var head = new Buffer(4); 182 | head[0] = (output.length >> 24) & 0xff; 183 | head[1] = (output.length >> 16) & 0xff; 184 | head[2] = (output.length >> 8) & 0xff; 185 | head[3] = output.length & 0xff; 186 | res.writeHead(200,{'Content-type': 'application/osmtile'}); 187 | if (chunked) { 188 | res.writeHead(200,{'Connection': 'close'}); 189 | } else { 190 | var content_length = output.length + 4; 191 | res.writeHead(200,{'Content-length': content_length}); 192 | res.useChunkedEncodingByDefault=false; 193 | res.chunkedEncoding=false; 194 | } 195 | res.write(head); 196 | } 197 | 198 | var server = http.createServer(function(req, res) { 199 | var uri = url.parse(req.url).pathname; 200 | if (!uri || uri == '/') { 201 | res.writeHead(200, {'Content-Type': 'text/html'}); 202 | return res.end(fs.readFileSync(path.join(root,'index.html'))); 203 | } 204 | if (uri == 'favicon.ico') { 205 | return error(res,''); 206 | } 207 | var filepath = path.join(root, uri); 208 | exists(filepath, function(exist) { 209 | var format = path.extname(uri); 210 | if (exist && (format == '.osmtile') && cache) { 211 | if (format == '.osmtile') { 212 | fs.readFile(filepath,function(err,output) { 213 | if (err) { 214 | console.log(err); 215 | return error(res,err.message); 216 | } 217 | osmtile_response(res,output); 218 | return res.end(output); 219 | }); 220 | } else { 221 | res.writeHead(200, {'Content-Type': mime.lookup(filepath)}); 222 | return res.end(fs.readFileSync(filepath)); 223 | } 224 | } else if (exist && (format != '.osmtile')) { 225 | res.writeHead(200, {'Content-Type': mime.lookup(filepath)}); 226 | return res.end(fs.readFileSync(filepath)); 227 | } else { 228 | parse_url(uri, function(err,params) { 229 | if (err) { 230 | console.log(err); 231 | return error(res,err.message); 232 | } 233 | map_pool.acquire(function(err, map) { 234 | if (err) { 235 | console.log(err); 236 | return error(res,err.message) 237 | } 238 | return renderer(map,params,res,filepath,cache); 239 | }); 240 | }); 241 | } 242 | }); 243 | }) 244 | 245 | if (debug) { 246 | server.on('connection',function(socket) { 247 | console.log('new connection'); 248 | }); 249 | 250 | server.on('closing',function() { 251 | console.log('closing') 252 | }); 253 | 254 | server.on('connect',function() { 255 | console.log('connect method') 256 | }); 257 | 258 | server.on('clientError',function(err) { 259 | console.log('clientError' + err.message) 260 | }); 261 | } 262 | 263 | server.listen(port); 264 | 265 | console.log('Vector tile server listening on port %d | directory %s', port, root); 266 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | // mapnik 24 | //#include 25 | //#include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "vector_renderer.hpp" 31 | #include "opensciencemap_backend.hpp" 32 | #include "opensciencemap_backend_pbf.hpp" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | int main(int argc, char** argv) 39 | { 40 | if (argc != 2) 41 | { 42 | std::cerr << "Usage: " << argv[0] << " " << std::endl; 43 | return EXIT_FAILURE; 44 | } 45 | 46 | mapnik::datasource_cache::instance().register_datasources("/opt/mapnik/lib/mapnik/input/"); 47 | mapnik::freetype_engine::register_fonts("/opt/mapnik/lib/mapnik/fonts/"); 48 | 49 | std::cerr << "vector tile server" << std::endl; 50 | std::string mapfile(argv[1]); 51 | 52 | mapnik::Map m(256,256); // tile map 53 | try 54 | { 55 | std::cerr << "loading " << mapfile << "..." << std::endl; 56 | mapnik::load_map(m, mapfile); 57 | //m.zoom_to_box(mapnik::box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)); 58 | //m.zoom_to_box(mapnik::box2d(-141233.598318,6756305.73374,-140782.086463,6756728.00478)); 59 | 60 | //mapnik::box2d bbox(-141233.598318,6755505.73374,-140782.086463,6756728.00478); 61 | //mapnik::box2d bbox(-141233.598318 + 1000,6755505.73374 + 1000,-140782.086463+1000,6756728.00478+1000); 62 | mapnik::box2d bbox(-141867.12449728712,6760702.277767269,-141255.62827100573,6761313.773993552); 63 | m.zoom_to_box(mapnik::box2d(bbox)); 64 | 65 | //m.zoom_to_box(mapnik::box2d(-144715.338031,6746062.31756,-133583.388952,6764043.36075)); 66 | } 67 | catch (...) 68 | { 69 | std::cerr << "Opps.." << std::endl; 70 | return EXIT_FAILURE; 71 | } 72 | 73 | std::string output; 74 | mapnik::opensciencemap_backend_pbf backend(output); 75 | mapnik::vector_renderer ren(m, backend); 76 | ren.apply(); 77 | 78 | std::cerr << "TILE TAGS SIZE=" << backend.tags().size() << std::endl; 79 | std::cerr << "TILE ELEM SIZE=" << backend.tile_elements().size() << std::endl; 80 | 81 | uint32_t bytes = backend.output_vector_tile(); 82 | std::string trimmed = output.substr(0,bytes); 83 | char head[4]; 84 | head[0] = (bytes >> 24) & 0xff; 85 | head[1] = (bytes >> 16) & 0xff; 86 | head[2] = (bytes >> 8) & 0xff; 87 | head[3] = bytes & 0xff; 88 | 89 | std::ofstream file("test.osmtile"); 90 | if (file) 91 | { 92 | file.write(head,4); 93 | file.write(trimmed.c_str(), trimmed.size()); 94 | } 95 | file.flush(); 96 | 97 | return EXIT_SUCCESS; 98 | } 99 | -------------------------------------------------------------------------------- /src/opensciencemap_backend.hpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef MAPNIK_OPENSCIENCEMAP_BACKEND_HPP 24 | #define MAPNIK_OPENSCIENCEMAP_BACKEND_HPP 25 | 26 | // protobuf io 27 | #include 28 | #include 29 | //boost 30 | #include 31 | #include 32 | #include "tags.hpp" 33 | #include 34 | 35 | namespace mapnik 36 | { 37 | 38 | typedef std::pair coord_type; 39 | typedef std::vector path_type; 40 | typedef std::vector tags_type; 41 | typedef std::vector index_type; 42 | 43 | struct tile_element 44 | { 45 | eGeomType type; 46 | tags_type tags; 47 | path_type path; 48 | index_type index; 49 | }; 50 | 51 | struct element_writer 52 | { 53 | google::protobuf::io::StringOutputStream raw_output_; 54 | google::protobuf::io::CodedOutputStream coded_output_; 55 | 56 | explicit element_writer(std::string & buffer) 57 | : raw_output_(&buffer), 58 | coded_output_(&raw_output_) 59 | {} 60 | 61 | void write_varint32(uint32_t val) 62 | { 63 | coded_output_.WriteVarint32(val); 64 | } 65 | 66 | void write_tag(uint32_t val) 67 | { 68 | coded_output_.WriteTag(val); 69 | } 70 | 71 | void write_string(std::string const& str) 72 | { 73 | coded_output_.WriteString(str); 74 | } 75 | 76 | void write_raw(char const * data, uint32_t size) 77 | { 78 | coded_output_.WriteRaw(const_cast(data),size); 79 | } 80 | 81 | uint32_t bytes_written() const 82 | { 83 | return coded_output_.ByteCount(); 84 | } 85 | }; 86 | 87 | const static double SCALE = 16.0; 88 | const static uint32_t TAGS_MAX = 627; 89 | 90 | struct opensciencemap_backend 91 | { 92 | private: 93 | std::vector tags_; 94 | std::vector custom_values_; 95 | boost::ptr_vector tile_elements_; 96 | std::auto_ptr element_; 97 | google::protobuf::io::StringOutputStream raw_output_; 98 | google::protobuf::io::CodedOutputStream coded_output_; 99 | public: 100 | explicit opensciencemap_backend(std::string & output) 101 | : raw_output_(&output), 102 | coded_output_(&raw_output_) 103 | {} 104 | 105 | boost::ptr_vector const& tile_elements() const 106 | { 107 | return tile_elements_; 108 | } 109 | std::vector const& tags() const 110 | { 111 | return tags_; 112 | } 113 | 114 | template 115 | void start_tile_element( T & feature, eGeomType type) 116 | { 117 | ///////////////////////////////////////////////////// 118 | element_.reset(new tile_element); 119 | element_->type = type; // geometry type POLY/LINE/POINT 120 | 121 | feature_kv_iterator itr = feature.begin(); 122 | feature_kv_iterator end = feature.end(); 123 | for ( ;itr!=end; ++itr) 124 | { 125 | std::string const& name = boost::get<0>(*itr); 126 | mapnik::value const& val = boost::get<1>(*itr); 127 | if (!val.is_null()) 128 | { 129 | boost::optional tag = tags::tag_index_from_kv(name,val.to_string()); 130 | if ( tag ) 131 | { 132 | if (*tag < TAGS_MAX) 133 | { 134 | element_->tags.push_back(*tag); 135 | } 136 | else 137 | { 138 | boost::optional tag_key = tags::tag_from_name(name); 139 | if (tag_key) 140 | { 141 | tags_.push_back(*tag_key); 142 | custom_values_.push_back(val.to_string()); 143 | element_->tags.push_back((1023 + tags_.size())); 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | 151 | void stop_tile_element() 152 | { 153 | tile_elements_.push_back(element_); 154 | } 155 | 156 | template 157 | void add_path(T & path) 158 | { 159 | vertex2d vtx(vertex2d::no_init); 160 | path.rewind(0); 161 | unsigned count = 0; 162 | int32_t x=0,y=0; 163 | 164 | if (element_.get()) 165 | { 166 | uint32_t start = element_->path.size(); 167 | while ((vtx.cmd = path.vertex(&vtx.x, &vtx.y)) != SEG_END) 168 | { 169 | int32_t cur_x = static_cast(vtx.x * SCALE); 170 | int32_t cur_y = static_cast(vtx.y * SCALE); 171 | int32_t dx = cur_x - x; 172 | int32_t dy = cur_y - y; 173 | if (count > 0 && vtx.cmd == SEG_LINETO && 174 | std::fabs(dx) < 1.0 && 175 | std::fabs(dy) < 1.0) 176 | { 177 | continue; 178 | } 179 | 180 | if (vtx.cmd == SEG_MOVETO && element_->path.size() > start) 181 | { 182 | uint32_t size = element_->path.size() - start; 183 | element_->index.push_back(size); 184 | start = element_->path.size(); 185 | } 186 | 187 | if (vtx.cmd == SEG_LINETO || vtx.cmd == SEG_MOVETO) 188 | { 189 | // zigzag encoding 190 | uint32_t xe = (dx << 1) ^ (dx >> 31); 191 | uint32_t ye = (dy << 1) ^ (dy >> 31); 192 | element_->path.push_back(coord_type(xe,ye)); 193 | } 194 | 195 | x = cur_x; 196 | y = cur_y; 197 | ++count; 198 | } 199 | if (element_->path.size() > start) 200 | { 201 | uint32_t size = element_->path.size() - start; 202 | element_->index.push_back(size); 203 | } 204 | } 205 | } 206 | 207 | uint32_t output_vector_tile() 208 | { 209 | // tile tags 210 | // num tags 211 | coded_output_.WriteTag(0x08); 212 | coded_output_.WriteVarint32(tags_.size()); 213 | coded_output_.WriteTag(0x12); 214 | 215 | std::string buffer; 216 | element_writer tag_writer(buffer); 217 | 218 | BOOST_FOREACH(tags::tag_type tag, tags_) 219 | { 220 | tag_writer.write_varint32(tag); 221 | } 222 | std::size_t bytes = tag_writer.bytes_written(); 223 | 224 | coded_output_.WriteVarint32(bytes); 225 | coded_output_.WriteRaw(buffer.data(), bytes); 226 | 227 | BOOST_FOREACH(std::string const& val, custom_values_) 228 | { 229 | coded_output_.WriteTag(0x1a); 230 | coded_output_.WriteVarint32(val.size()); 231 | coded_output_.WriteRaw(val.data(),val.size()); 232 | } 233 | 234 | // output tile elements 235 | BOOST_FOREACH(tile_element const& elem, tile_elements_) 236 | { 237 | if (elem.tags.size() > 0 && !elem.path.empty()) 238 | { 239 | if (elem.type == Polygon) 240 | coded_output_.WriteTag(0x62); 241 | else if (elem.type == LineString) 242 | coded_output_.WriteTag(0x5a); 243 | else if (elem.type == Point) 244 | coded_output_.WriteTag(0x6a); 245 | 246 | // ELEMENT 247 | std::size_t element_bytes=0; 248 | std::string element_buffer; 249 | 250 | { 251 | // ELEMENT TAGS 252 | std::string tags_buffer; 253 | element_writer writer(tags_buffer); 254 | writer.write_tag(0x5a); 255 | std::string element_tags; 256 | uint32_t tags_bytes = output_short_array(element_tags,elem.tags); 257 | writer.write_varint32(tags_bytes); 258 | writer.write_raw(element_tags.data(), tags_bytes); 259 | element_bytes += writer.bytes_written(); 260 | element_buffer+=tags_buffer.substr(0,writer.bytes_written()); 261 | } 262 | 263 | if (elem.index.size() > 1) 264 | { 265 | //TAG_ELEM_NUM_INDICES 266 | std::string indices_buffer; 267 | element_writer writer(indices_buffer); 268 | writer.write_tag(0x08); 269 | writer.write_varint32(elem.index.size()); 270 | element_bytes += writer.bytes_written(); 271 | element_buffer+=indices_buffer.substr(0,writer.bytes_written()); 272 | } 273 | 274 | if (elem.type != Point) 275 | { 276 | // TAG_ELEM_INDEX 277 | std::string index_buffer; 278 | element_writer writer(index_buffer); 279 | writer.write_tag(0x62); 280 | std::string array_buffer; 281 | uint32_t array_bytes = output_short_array(array_buffer,elem.index); 282 | writer.write_varint32(array_bytes); 283 | writer.write_raw(array_buffer.data(),array_bytes); 284 | element_bytes += writer.bytes_written(); 285 | element_buffer+=index_buffer.substr(0, writer.bytes_written()); 286 | } 287 | 288 | // COORDS 289 | { 290 | std::string coord_buffer; 291 | element_writer writer(coord_buffer); 292 | writer.write_tag(0x6a); 293 | std::string element_paths; 294 | uint32_t paths_bytes = output_element_paths(element_paths,elem.path); 295 | writer.write_varint32(paths_bytes); 296 | writer.write_raw(element_paths.data(),paths_bytes); 297 | element_bytes += writer.bytes_written(); 298 | element_buffer+=coord_buffer.substr(0,writer.bytes_written()); 299 | } 300 | // write element 301 | coded_output_.WriteVarint32(element_bytes); 302 | coded_output_.WriteRaw(element_buffer.data(), element_bytes); 303 | } 304 | } 305 | return coded_output_.ByteCount(); 306 | } 307 | 308 | template 309 | uint32_t output_short_array(std::string & buffer, Array const& ar) 310 | { 311 | element_writer writer(buffer); 312 | BOOST_FOREACH(typename Array::value_type elem, ar) 313 | { 314 | writer.write_varint32(elem); 315 | } 316 | return writer.bytes_written(); 317 | } 318 | 319 | template 320 | uint32_t output_element_paths(std::string & buffer, Path const& path) 321 | { 322 | element_writer writer(buffer); 323 | BOOST_FOREACH(coord_type c, path) 324 | { 325 | writer.write_varint32(c.first); 326 | writer.write_varint32(c.second); 327 | } 328 | return writer.bytes_written(); 329 | } 330 | 331 | }; 332 | } 333 | 334 | #endif //MAPNIK_OPENSCIENCEMAP_BACKEND_HPP 335 | -------------------------------------------------------------------------------- /src/opensciencemap_backend_pbf.hpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef MAPNIK_OPENSCIENCEMAP_BACKEND_PBF_HPP 24 | #define MAPNIK_OPENSCIENCEMAP_BACKEND_PBF_HPP 25 | 26 | //boost 27 | #include 28 | #include 29 | 30 | //// 31 | #include "tags.hpp" 32 | #include "TileData.pb.h" 33 | // stl 34 | #include 35 | 36 | namespace mapnik 37 | { 38 | 39 | using org::oscim::database::oscimap::Data; 40 | using org::oscim::database::oscimap::Data_Element; 41 | 42 | typedef std::pair coord_type; 43 | typedef std::vector path_type; 44 | typedef std::vector tags_type; 45 | typedef std::vector index_type; 46 | 47 | struct opensciencemap_backend_pbf 48 | { 49 | struct tile_element 50 | { 51 | eGeomType type; 52 | tags_type tags; 53 | path_type path; 54 | index_type index; 55 | }; 56 | 57 | private: 58 | const double SCALE; 59 | const uint32_t TAGS_MAX; 60 | std::vector tags_; 61 | std::vector custom_values_; 62 | boost::ptr_vector tile_elements_; 63 | std::auto_ptr element_; 64 | std::string & output_; 65 | public: 66 | explicit opensciencemap_backend_pbf(std::string & output) 67 | : SCALE(16.0), 68 | TAGS_MAX(627), 69 | output_(output) 70 | {} 71 | 72 | boost::ptr_vector const& tile_elements() const 73 | { 74 | return tile_elements_; 75 | } 76 | std::vector const& tags() const 77 | { 78 | return tags_; 79 | } 80 | 81 | template 82 | void start_tile_element( T & feature, eGeomType type) 83 | { 84 | ///////////////////////////////////////////////////// 85 | element_.reset(new tile_element); 86 | element_->type = type; // geometry type POLY/LINE/POINT 87 | 88 | feature_kv_iterator itr = feature.begin(); 89 | feature_kv_iterator end = feature.end(); 90 | for ( ;itr!=end; ++itr) 91 | { 92 | std::string const& name = boost::get<0>(*itr); 93 | mapnik::value const& val = boost::get<1>(*itr); 94 | if (!val.is_null()) 95 | { 96 | boost::optional tag = tags::tag_index_from_kv(name,val.to_string()); 97 | if ( tag ) 98 | { 99 | if (*tag < TAGS_MAX) 100 | { 101 | element_->tags.push_back(*tag); 102 | } 103 | else 104 | { 105 | boost::optional tag_key = tags::tag_from_name(name); 106 | if (tag_key) 107 | { 108 | tags_.push_back(*tag_key); 109 | custom_values_.push_back(val.to_string()); 110 | element_->tags.push_back((1023 + tags_.size())); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | void stop_tile_element() 119 | { 120 | tile_elements_.push_back(element_); 121 | } 122 | 123 | template 124 | void add_path(T & path) 125 | { 126 | vertex2d vtx(vertex2d::no_init); 127 | path.rewind(0); 128 | unsigned count = 0; 129 | int32_t x=0,y=0; 130 | 131 | if (element_.get()) 132 | { 133 | uint32_t start = element_->path.size(); 134 | while ((vtx.cmd = path.vertex(&vtx.x, &vtx.y)) != SEG_END) 135 | { 136 | int32_t cur_x = static_cast(vtx.x * SCALE); 137 | int32_t cur_y = static_cast(vtx.y * SCALE); 138 | int32_t dx = cur_x - x; 139 | int32_t dy = cur_y - y; 140 | if (count > 0 && vtx.cmd == SEG_LINETO && 141 | std::fabs(dx) < 1.0 && 142 | std::fabs(dy) < 1.0) 143 | { 144 | continue; 145 | } 146 | 147 | if (vtx.cmd == SEG_MOVETO && element_->path.size() > start) 148 | { 149 | uint32_t size = element_->path.size() - start; 150 | element_->index.push_back(size); 151 | start = element_->path.size(); 152 | } 153 | 154 | if (vtx.cmd == SEG_LINETO || vtx.cmd == SEG_MOVETO) 155 | { 156 | element_->path.push_back(coord_type(dx,dy)); 157 | } 158 | 159 | x = cur_x; 160 | y = cur_y; 161 | ++count; 162 | } 163 | if (element_->path.size() > start) 164 | { 165 | uint32_t size = element_->path.size() - start; 166 | element_->index.push_back(size); 167 | } 168 | } 169 | } 170 | 171 | uint32_t output_vector_tile() 172 | { 173 | Data data; 174 | data.set_num_tags(tags_.size()); 175 | 176 | BOOST_FOREACH(tags::tag_type tag, tags_) 177 | { 178 | data.add_keys(tag); 179 | } 180 | 181 | BOOST_FOREACH(std::string const& val, custom_values_) 182 | { 183 | data.add_values(val); 184 | } 185 | 186 | // output tile elements 187 | BOOST_FOREACH(tile_element const& elem, tile_elements_) 188 | { 189 | if (elem.tags.size() > 0 && !elem.path.empty()) 190 | { 191 | Data_Element * element = 0; 192 | if (elem.type == Polygon) 193 | element = data.add_polygons(); 194 | else if (elem.type == LineString) 195 | element = data.add_lines(); 196 | else if (elem.type == Point) 197 | element = data.add_points(); 198 | 199 | if (element) 200 | { 201 | // optional uint32 num_indices = 1 [default = 1]; 202 | if (elem.index.size() > 1) 203 | { 204 | element->set_num_indices(elem.index.size()); 205 | } 206 | 207 | // repeated uint32 tags = 11 [packed = true]; 208 | BOOST_FOREACH( tags_type::value_type tag , elem.tags) 209 | { 210 | element->add_tags(tag); 211 | } 212 | 213 | if (elem.type != Point) 214 | { 215 | // repeated uint32 indices = 12 [packed = true]; 216 | BOOST_FOREACH(index_type::value_type index, elem.index) 217 | { 218 | element->add_indices(index); 219 | } 220 | } 221 | // repeated sint32 coordinates = 13 [packed = true]; 222 | BOOST_FOREACH(coord_type c, elem.path) 223 | { 224 | element->add_coordinates(c.first); 225 | element->add_coordinates(c.second); 226 | } 227 | } 228 | } 229 | } 230 | if (data.SerializeToString(&output_)) 231 | { 232 | return data.ByteSize(); 233 | } 234 | else 235 | { 236 | return 0; 237 | } 238 | } 239 | }; 240 | } 241 | 242 | #endif //MAPNIK_OPENSCIENCEMAP_BACKEND_PBF_HPP 243 | -------------------------------------------------------------------------------- /src/tags.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #include "tags.hpp" 24 | 25 | // boost 26 | #include 27 | #include 28 | 29 | namespace mapnik { namespace tags { 30 | 31 | typedef boost::bimap tag_lookup_type; 32 | typedef boost::bimap > tag_value_lookup_type; 33 | 34 | static const tag_lookup_type tag_lookup = boost::assign::list_of 35 | (0,"access") 36 | (1,"addr:housename") 37 | (2,"addr:housenumber") 38 | (3,"addr:interpolation") 39 | (4,"admin_level") 40 | (5,"aerialway") 41 | (6,"aeroway") 42 | (7 ,"amenity") 43 | (8 ,"area") 44 | (9 ,"barrier") 45 | (10 ,"bicycle") 46 | (11 ,"brand") 47 | (12 ,"bridge") 48 | (13 ,"boundary") 49 | (14 ,"building") 50 | (15 ,"construction") 51 | (16 ,"covered") 52 | (17 ,"culvert") 53 | (18 ,"cutting") 54 | (19 ,"denomination") 55 | (20 ,"disused") 56 | (21 ,"embankment") 57 | (22 ,"foot") 58 | (23 ,"generator:source") 59 | (24 ,"harbour") 60 | (25 ,"highway") 61 | (26 ,"historic") 62 | (27 ,"horse") 63 | (28 ,"intermittent") 64 | (29 ,"junction") 65 | (30 ,"landuse") 66 | (31 ,"layer") 67 | (32 ,"leisure") 68 | (33 ,"lock") 69 | (34 ,"man_made") 70 | (35 ,"military") 71 | (36 ,"motorcar") 72 | (37 ,"name") 73 | (38 ,"natural") 74 | (39 ,"oneway") 75 | (40 ,"operator") 76 | (41 ,"population") 77 | (42 ,"power") 78 | (43 ,"power_source") 79 | (44 ,"place") 80 | (45 ,"railway") 81 | (46 ,"ref") 82 | (47 ,"religion") 83 | (48 ,"route") 84 | (49 ,"service") 85 | (50 ,"shop") 86 | (51 ,"sport") 87 | (52 ,"surface") 88 | (53 ,"toll") 89 | (54 ,"tourism") 90 | (55 ,"tower:type") 91 | (56 ,"tracktype") 92 | (57 ,"tunnel") 93 | (58 ,"water") 94 | (59 ,"waterway") 95 | (60 ,"wetland") 96 | (61 ,"width") 97 | (62 ,"wood") 98 | ; 99 | 100 | static const tag_value_lookup_type tag_value_lookup = boost::assign::list_of 101 | (0,std::make_pair("building","yes")) 102 | (1,std::make_pair("highway","residential")) 103 | (2,std::make_pair("highway","service")) 104 | (3,std::make_pair("waterway","stream")) 105 | (4,std::make_pair("highway","unclassified")) 106 | (5,std::make_pair("highway","track")) 107 | (6,std::make_pair("oneway","yes")) 108 | (7,std::make_pair("natural","water")) 109 | (8,std::make_pair("highway","footway")) 110 | (9,std::make_pair("access","private")) 111 | (10,std::make_pair("highway","tertiary")) 112 | (11,std::make_pair("highway","path")) 113 | (12,std::make_pair("highway","secondary")) 114 | (13,std::make_pair("landuse","forest")) 115 | (14,std::make_pair("bridge","yes")) 116 | (15,std::make_pair("natural","tree")) 117 | (16,std::make_pair("surface","paved")) 118 | (17,std::make_pair("natural","wood")) 119 | (18,std::make_pair("highway","primary")) 120 | (19,std::make_pair("landuse","grass")) 121 | (20,std::make_pair("landuse","residential")) 122 | (21,std::make_pair("surface","unpaved")) 123 | (22,std::make_pair("highway","bus_stop")) 124 | (23,std::make_pair("surface","asphalt")) 125 | (24,std::make_pair("bicycle","yes")) 126 | (25,std::make_pair("amenity","parking")) 127 | (26,std::make_pair("place","locality")) 128 | (27,std::make_pair("railway","rail")) 129 | (28,std::make_pair("service","parking_aisle")) 130 | (29,std::make_pair("boundary","administrative")) 131 | (30,std::make_pair("building","house")) 132 | (31,std::make_pair("place","village")) 133 | (32,std::make_pair("natural","coastline")) 134 | (33,std::make_pair("tracktype","grade2")) 135 | (34,std::make_pair("oneway","no")) 136 | (35,std::make_pair("service","driveway")) 137 | (36,std::make_pair("highway","turning_circle")) 138 | (37,std::make_pair("place","hamlet")) 139 | (38,std::make_pair("natural","wetland")) 140 | (39,std::make_pair("tracktype","grade3")) 141 | (40,std::make_pair("waterway","river")) 142 | (41,std::make_pair("highway","cycleway")) 143 | (42,std::make_pair("barrier","fence")) 144 | (43,std::make_pair("building","residential")) 145 | (44,std::make_pair("amenity","school")) 146 | (45,std::make_pair("highway","crossing")) 147 | (46,std::make_pair("admin_level","8")) 148 | (47,std::make_pair("highway","trunk")) 149 | (48,std::make_pair("amenity","place_of_worship")) 150 | (49,std::make_pair("landuse","farmland")) 151 | (50,std::make_pair("tracktype","grade1")) 152 | (51,std::make_pair("highway","road")) 153 | (52,std::make_pair("landuse","farm")) 154 | (53,std::make_pair("surface","gravel")) 155 | (54,std::make_pair("landuse","meadow")) 156 | (55,std::make_pair("highway","motorway")) 157 | (56,std::make_pair("highway","traffic_signals")) 158 | (57,std::make_pair("building","hut")) 159 | (58,std::make_pair("highway","motorway_link")) 160 | (59,std::make_pair("tracktype","grade4")) 161 | (60,std::make_pair("barrier","gate")) 162 | (61,std::make_pair("highway","living_street")) 163 | (62,std::make_pair("bicycle","no")) 164 | (63,std::make_pair("leisure","pitch")) 165 | (64,std::make_pair("tunnel","yes")) 166 | (65,std::make_pair("surface","ground")) 167 | (66,std::make_pair("highway","steps")) 168 | (67,std::make_pair("natural","land")) 169 | (68,std::make_pair("man_made","survey_point")) 170 | (69,std::make_pair("tracktype","grade5")) 171 | (70,std::make_pair("waterway","ditch")) 172 | (71,std::make_pair("leisure","park")) 173 | (72,std::make_pair("amenity","restaurant")) 174 | (73,std::make_pair("barrier","wall")) 175 | (74,std::make_pair("waterway","riverbank")) 176 | (75,std::make_pair("amenity","bench")) 177 | (76,std::make_pair("building","garage")) 178 | (77,std::make_pair("natural","scrub")) 179 | (78,std::make_pair("highway","pedestrian")) 180 | (79,std::make_pair("natural","peak")) 181 | (80,std::make_pair("building","entrance")) 182 | (81,std::make_pair("landuse","reservoir")) 183 | (82,std::make_pair("access","yes")) 184 | (83,std::make_pair("bicycle","designated")) 185 | (84,std::make_pair("leisure","swimming_pool")) 186 | (85,std::make_pair("landuse","farmyard")) 187 | (86,std::make_pair("railway","level_crossing")) 188 | (87,std::make_pair("building","apartments")) 189 | (88,std::make_pair("surface","grass")) 190 | (89,std::make_pair("wheelchair","yes")) 191 | (90,std::make_pair("service","alley")) 192 | (91,std::make_pair("landuse","industrial")) 193 | (92,std::make_pair("amenity","fuel")) 194 | (93,std::make_pair("surface","dirt")) 195 | (94,std::make_pair("highway","trunk_link")) 196 | (95,std::make_pair("waterway","drain")) 197 | (96,std::make_pair("barrier","hedge")) 198 | (97,std::make_pair("amenity","grave_yard")) 199 | (98,std::make_pair("tourism","information")) 200 | (99,std::make_pair("shop","supermarket")) 201 | (100,std::make_pair("highway","primary_link")) 202 | (101,std::make_pair("wood","deciduous")) 203 | (102,std::make_pair("leisure","playground")) 204 | (103,std::make_pair("building","roof")) 205 | (104,std::make_pair("building","industrial")) 206 | (105,std::make_pair("amenity","post_box")) 207 | (106,std::make_pair("waterway","canal")) 208 | (107,std::make_pair("barrier","bollard")) 209 | (108,std::make_pair("leisure","garden")) 210 | (109,std::make_pair("wood","mixed")) 211 | (110,std::make_pair("landuse","cemetery")) 212 | (111,std::make_pair("landuse","orchard")) 213 | (112,std::make_pair("shop","convenience")) 214 | (113,std::make_pair("access","permissive")) 215 | (114,std::make_pair("surface","concrete")) 216 | (115,std::make_pair("surface","paving_stones")) 217 | (116,std::make_pair("service","spur")) 218 | (117,std::make_pair("building","garages")) 219 | (118,std::make_pair("amenity","bank")) 220 | (119,std::make_pair("tourism","hotel")) 221 | (120,std::make_pair("access","no")) 222 | (121,std::make_pair("amenity","fast_food")) 223 | (122,std::make_pair("man_made","pier")) 224 | (123,std::make_pair("amenity","kindergarten")) 225 | (124,std::make_pair("access","agricultural")) 226 | (125,std::make_pair("surface","cobblestone")) 227 | (126,std::make_pair("wheelchair","no")) 228 | (127,std::make_pair("amenity","cafe")) 229 | (128,std::make_pair("amenity","hospital")) 230 | (129,std::make_pair("amenity","post_office")) 231 | (130,std::make_pair("amenity","public_building")) 232 | (131,std::make_pair("amenity","recycling")) 233 | (132,std::make_pair("highway","street_lamp")) 234 | (133,std::make_pair("man_made","tower")) 235 | (134,std::make_pair("waterway","dam")) 236 | (135,std::make_pair("amenity","pub")) 237 | (136,std::make_pair("wood","coniferous")) 238 | (137,std::make_pair("access","destination")) 239 | (138,std::make_pair("admin_level","6")) 240 | (139,std::make_pair("landuse","commercial")) 241 | (140,std::make_pair("amenity","pharmacy")) 242 | (141,std::make_pair("railway","abandoned")) 243 | (142,std::make_pair("service","yard")) 244 | (143,std::make_pair("place","island")) 245 | (144,std::make_pair("oneway","_1")) 246 | (145,std::make_pair("landuse","quarry")) 247 | (146,std::make_pair("landuse","vineyard")) 248 | (147,std::make_pair("highway","motorway_junction")) 249 | (148,std::make_pair("railway","station")) 250 | (149,std::make_pair("landuse","allotments")) 251 | (150,std::make_pair("barrier","lift_gate")) 252 | (151,std::make_pair("admin_level","10")) 253 | (152,std::make_pair("amenity","telephone")) 254 | (153,std::make_pair("place","town")) 255 | (154,std::make_pair("man_made","cutline")) 256 | (155,std::make_pair("place","suburb")) 257 | (156,std::make_pair("aeroway","taxiway")) 258 | (157,std::make_pair("wheelchair","limited")) 259 | (158,std::make_pair("highway","secondary_link")) 260 | (159,std::make_pair("leisure","sports_centre")) 261 | (160,std::make_pair("amenity","bicycle_parking")) 262 | (161,std::make_pair("surface","sand")) 263 | (162,std::make_pair("highway","stop")) 264 | (163,std::make_pair("man_made","works")) 265 | (164,std::make_pair("landuse","retail")) 266 | (165,std::make_pair("amenity","fire_station")) 267 | (166,std::make_pair("service","siding")) 268 | (167,std::make_pair("amenity","toilets")) 269 | (168,std::make_pair("bench","yes")) 270 | (169,std::make_pair("oneway","1")) 271 | (170,std::make_pair("surface","compacted")) 272 | (171,std::make_pair("landuse","basin")) 273 | (172,std::make_pair("amenity","police")) 274 | (173,std::make_pair("railway","tram")) 275 | (174,std::make_pair("route","road")) 276 | (175,std::make_pair("natural","cliff")) 277 | (176,std::make_pair("highway","construction")) 278 | (177,std::make_pair("aeroway","aerodrome")) 279 | (178,std::make_pair("entrance","yes")) 280 | (179,std::make_pair("man_made","storage_tank")) 281 | (180,std::make_pair("amenity","atm")) 282 | (181,std::make_pair("tourism","attraction")) 283 | (182,std::make_pair("route","bus")) 284 | (183,std::make_pair("shop","bakery")) 285 | (184,std::make_pair("tourism","viewpoint")) 286 | (185,std::make_pair("amenity","swimming_pool")) 287 | (186,std::make_pair("natural","beach")) 288 | (187,std::make_pair("tourism","picnic_site")) 289 | (188,std::make_pair("oneway","true")) 290 | (189,std::make_pair("highway","bridleway")) 291 | (190,std::make_pair("tourism","camp_site")) 292 | (191,std::make_pair("abutters","residential")) 293 | (192,std::make_pair("leisure","nature_reserve")) 294 | (193,std::make_pair("amenity","drinking_water")) 295 | (194,std::make_pair("shop","clothes")) 296 | (195,std::make_pair("natural","heath")) 297 | (196,std::make_pair("highway","mini_roundabout")) 298 | (197,std::make_pair("landuse","construction")) 299 | (198,std::make_pair("amenity","waste_basket")) 300 | (199,std::make_pair("railway","platform")) 301 | (200,std::make_pair("amenity","townhall")) 302 | (201,std::make_pair("shop","hairdresser")) 303 | (202,std::make_pair("amenity","shelter")) 304 | (203,std::make_pair("admin_level","9")) 305 | (204,std::make_pair("building","farm_auxiliary")) 306 | (205,std::make_pair("amenity","library")) 307 | (206,std::make_pair("building","detached")) 308 | (207,std::make_pair("admin_level","4")) 309 | (208,std::make_pair("landuse","village_green")) 310 | (209,std::make_pair("barrier","stile")) 311 | (210,std::make_pair("landuse","garages")) 312 | (211,std::make_pair("amenity","bar")) 313 | (212,std::make_pair("railway","buffer_stop")) 314 | (213,std::make_pair("wetland","marsh")) 315 | (214,std::make_pair("tourism","museum")) 316 | (215,std::make_pair("barrier","cycle_barrier")) 317 | (216,std::make_pair("route","bicycle")) 318 | (217,std::make_pair("railway","tram_stop")) 319 | (218,std::make_pair("amenity","parking_space")) 320 | (219,std::make_pair("barrier","retaining_wall")) 321 | (220,std::make_pair("landuse","recreation_ground")) 322 | (221,std::make_pair("amenity","university")) 323 | (222,std::make_pair("highway","tertiary_link")) 324 | (223,std::make_pair("building","terrace")) 325 | (224,std::make_pair("shop","car_repair")) 326 | (225,std::make_pair("amenity","hunting_stand")) 327 | (226,std::make_pair("amenity","fountain")) 328 | (227,std::make_pair("man_made","pipeline")) 329 | (228,std::make_pair("wetland","swamp")) 330 | (229,std::make_pair("shop","car")) 331 | (230,std::make_pair("bench","no")) 332 | (231,std::make_pair("tunnel","culvert")) 333 | (232,std::make_pair("building","school")) 334 | (233,std::make_pair("barrier","entrance")) 335 | (234,std::make_pair("railway","disused")) 336 | (235,std::make_pair("railway","crossing")) 337 | (236,std::make_pair("building","church")) 338 | (237,std::make_pair("amenity","social_facility")) 339 | (238,std::make_pair("natural","bay")) 340 | (239,std::make_pair("shop","kiosk")) 341 | (240,std::make_pair("amenity","vending_machine")) 342 | (241,std::make_pair("route","hiking")) 343 | (242,std::make_pair("natural","spring")) 344 | (243,std::make_pair("leisure","common")) 345 | (244,std::make_pair("railway","switch")) 346 | (245,std::make_pair("waterway","rapids")) 347 | (246,std::make_pair("admin_level","7")) 348 | (247,std::make_pair("leisure","stadium")) 349 | (248,std::make_pair("leisure","track")) 350 | (249,std::make_pair("place","isolated_dwelling")) 351 | (250,std::make_pair("place","islet")) 352 | (251,std::make_pair("waterway","weir")) 353 | (252,std::make_pair("amenity","doctors")) 354 | (253,std::make_pair("access","designated")) 355 | (254,std::make_pair("landuse","conservation")) 356 | (255,std::make_pair("waterway","artificial")) 357 | (256,std::make_pair("amenity","bus_station")) 358 | (257,std::make_pair("leisure","golf_course")) 359 | (258,std::make_pair("shop","doityourself")) 360 | (259,std::make_pair("building","service")) 361 | (260,std::make_pair("tourism","guest_house")) 362 | (261,std::make_pair("aeroway","runway")) 363 | (262,std::make_pair("place","city")) 364 | (263,std::make_pair("railway","subway")) 365 | (264,std::make_pair("man_made","wastewater_plant")) 366 | (265,std::make_pair("building","commercial")) 367 | (266,std::make_pair("railway","halt")) 368 | (267,std::make_pair("amenity","emergency_phone")) 369 | (268,std::make_pair("building","retail")) 370 | (269,std::make_pair("barrier","block")) 371 | (270,std::make_pair("leisure","recreation_ground")) 372 | (271,std::make_pair("access","forestry")) 373 | (272,std::make_pair("amenity","college")) 374 | (273,std::make_pair("highway","platform")) 375 | (274,std::make_pair("access","unknown")) 376 | (275,std::make_pair("man_made","water_tower")) 377 | (276,std::make_pair("surface","pebblestone")) 378 | (277,std::make_pair("bridge","viaduct")) 379 | (278,std::make_pair("shop","butcher")) 380 | (279,std::make_pair("shop","florist")) 381 | (280,std::make_pair("boundary","landuse")) 382 | (281,std::make_pair("aeroway","helipad")) 383 | (282,std::make_pair("building","hangar")) 384 | (283,std::make_pair("natural","glacier")) 385 | (284,std::make_pair("highway","proposed")) 386 | (285,std::make_pair("shop","mall")) 387 | (286,std::make_pair("barrier","toll_booth")) 388 | (287,std::make_pair("amenity","fire_hydrant")) 389 | (288,std::make_pair("building","manufacture")) 390 | (289,std::make_pair("building","farm")) 391 | (290,std::make_pair("surface","wood")) 392 | (291,std::make_pair("amenity","car_wash")) 393 | (292,std::make_pair("amenity","dentist")) 394 | (293,std::make_pair("natural","marsh")) 395 | (294,std::make_pair("man_made","surveillance")) 396 | (295,std::make_pair("shop","bicycle")) 397 | (296,std::make_pair("route","foot")) 398 | (297,std::make_pair("amenity","theatre")) 399 | (298,std::make_pair("building","office")) 400 | (299,std::make_pair("railway","light_rail")) 401 | (300,std::make_pair("man_made","petroleum_well")) 402 | (301,std::make_pair("amenity","taxi")) 403 | (302,std::make_pair("building","greenhouse")) 404 | (303,std::make_pair("landuse","brownfield")) 405 | (304,std::make_pair("bicycle","permissive")) 406 | (305,std::make_pair("admin_level","2")) 407 | (306,std::make_pair("aeroway","apron")) 408 | (307,std::make_pair("building","cabin")) 409 | (308,std::make_pair("amenity","cinema")) 410 | (309,std::make_pair("access","customers")) 411 | (310,std::make_pair("tourism","motel")) 412 | (311,std::make_pair("railway","narrow_gauge")) 413 | (312,std::make_pair("amenity","marketplace")) 414 | (313,std::make_pair("shop","furniture")) 415 | (314,std::make_pair("entrance","staircase")) 416 | (315,std::make_pair("tourism","artwork")) 417 | (316,std::make_pair("natural","grassland")) 418 | (317,std::make_pair("shop","books")) 419 | (318,std::make_pair("admin_level","5")) 420 | (319,std::make_pair("man_made","groyne")) 421 | (320,std::make_pair("waterway","lock_gate")) 422 | (321,std::make_pair("highway","emergency_access_point")) 423 | (322,std::make_pair("natural","sand")) 424 | (323,std::make_pair("landuse","military")) 425 | (324,std::make_pair("boundary","protected_area")) 426 | (325,std::make_pair("amenity","community_centre")) 427 | (326,std::make_pair("barrier","kissing_gate")) 428 | (327,std::make_pair("highway","speed_camera")) 429 | (328,std::make_pair("boundary","national_park")) 430 | (329,std::make_pair("railway","subway_entrance")) 431 | (330,std::make_pair("man_made","silo")) 432 | (331,std::make_pair("shop","alcohol")) 433 | (332,std::make_pair("highway","give_way")) 434 | (333,std::make_pair("leisure","slipway")) 435 | (334,std::make_pair("shop","electronics")) 436 | (335,std::make_pair("bicycle","dismount")) 437 | (336,std::make_pair("leisure","marina")) 438 | (337,std::make_pair("entrance","main")) 439 | (338,std::make_pair("boundary","postal_code")) 440 | (339,std::make_pair("landuse","greenhouse_horticulture")) 441 | (340,std::make_pair("highway","milestone")) 442 | (341,std::make_pair("natural","cave_entrance")) 443 | (342,std::make_pair("landuse","landfill")) 444 | (343,std::make_pair("shop","chemist")) 445 | (344,std::make_pair("shop","shoes")) 446 | (345,std::make_pair("barrier","cattle_grid")) 447 | (346,std::make_pair("landuse","railway")) 448 | (347,std::make_pair("tourism","hostel")) 449 | (348,std::make_pair("tourism","chalet")) 450 | (349,std::make_pair("place","county")) 451 | (350,std::make_pair("shop","department_store")) 452 | (351,std::make_pair("highway","ford")) 453 | (352,std::make_pair("natural","scree")) 454 | (353,std::make_pair("landuse","greenfield")) 455 | (354,std::make_pair("amenity","nursing_home")) 456 | (355,std::make_pair("barrier","wire_fence")) 457 | (356,std::make_pair("access","restricted")) 458 | (357,std::make_pair("man_made","reservoir_covered")) 459 | (358,std::make_pair("amenity","bicycle_rental")) 460 | (359,std::make_pair("man_made","MDF")) 461 | (360,std::make_pair("man_made","water_well")) 462 | (361,std::make_pair("landuse","field")) 463 | (362,std::make_pair("landuse","wood")) 464 | (363,std::make_pair("shop","hardware")) 465 | (364,std::make_pair("tourism","alpine_hut")) 466 | (365,std::make_pair("natural","tree_row")) 467 | (366,std::make_pair("tourism","caravan_site")) 468 | (367,std::make_pair("bridge","no")) 469 | (368,std::make_pair("wetland","bog")) 470 | (369,std::make_pair("amenity","courthouse")) 471 | (370,std::make_pair("route","ferry")) 472 | (371,std::make_pair("barrier","city_wall")) 473 | (372,std::make_pair("amenity","veterinary")) 474 | (373,std::make_pair("shop","jewelry")) 475 | (374,std::make_pair("building","transportation")) 476 | (375,std::make_pair("amenity","arts_centre")) 477 | (376,std::make_pair("bicycle","official")) 478 | (377,std::make_pair("shop","optician")) 479 | (378,std::make_pair("shop","yes")) 480 | (379,std::make_pair("building","collapsed")) 481 | (380,std::make_pair("shop","garden_centre")) 482 | (381,std::make_pair("man_made","chimney")) 483 | (382,std::make_pair("man_made","mine")) 484 | (383,std::make_pair("bench","unknown")) 485 | (384,std::make_pair("railway","preserved")) 486 | (385,std::make_pair("building","public")) 487 | (386,std::make_pair("amenity","ferry_terminal")) 488 | (387,std::make_pair("highway","raceway")) 489 | (388,std::make_pair("natural","rock")) 490 | (389,std::make_pair("tunnel","no")) 491 | (390,std::make_pair("building","university")) 492 | (391,std::make_pair("shop","beverages")) 493 | (392,std::make_pair("amenity","waste_disposal")) 494 | (393,std::make_pair("building","warehouse")) 495 | (394,std::make_pair("leisure","water_park")) 496 | (395,std::make_pair("shop","gift")) 497 | (396,std::make_pair("place","farm")) 498 | (397,std::make_pair("wetland","tidalflat")) 499 | (398,std::make_pair("waterway","waterfall")) 500 | (399,std::make_pair("man_made","dolphin")) 501 | (400,std::make_pair("service","drive_through")) 502 | (401,std::make_pair("amenity","nightclub")) 503 | (402,std::make_pair("building","shed")) 504 | (403,std::make_pair("shop","greengrocer")) 505 | (404,std::make_pair("natural","fell")) 506 | (405,std::make_pair("wetland","wet_meadow")) 507 | (406,std::make_pair("aeroway","gate")) 508 | (407,std::make_pair("shop","computer")) 509 | (408,std::make_pair("man_made","lighthouse")) 510 | (409,std::make_pair("wetland","reedbed")) 511 | (410,std::make_pair("man_made","breakwater")) 512 | (411,std::make_pair("surface","Dirt_Sand")) 513 | (412,std::make_pair("barrier","ditch")) 514 | (413,std::make_pair("barrier","yes")) 515 | (414,std::make_pair("amenity","biergarten")) 516 | (415,std::make_pair("shop","mobile_phone")) 517 | (416,std::make_pair("route","mtb")) 518 | (417,std::make_pair("amenity","grit_bin")) 519 | (418,std::make_pair("amenity","bbq")) 520 | (419,std::make_pair("shop","sports")) 521 | (420,std::make_pair("barrier","wood_fence")) 522 | (421,std::make_pair("entrance","home")) 523 | (422,std::make_pair("shop","laundry")) 524 | (423,std::make_pair("man_made","gasometer")) 525 | (424,std::make_pair("barrier","embankment")) 526 | (425,std::make_pair("shop","toys")) 527 | (426,std::make_pair("wetland","saltmarsh")) 528 | (427,std::make_pair("waterway","soakhole")) 529 | (428,std::make_pair("shop","travel_agency")) 530 | (429,std::make_pair("man_made","water_works")) 531 | (430,std::make_pair("route","railway")) 532 | (431,std::make_pair("amenity","prison")) 533 | (432,std::make_pair("highway","rest_area")) 534 | (433,std::make_pair("shop","stationery")) 535 | (434,std::make_pair("admin_level","11")) 536 | (435,std::make_pair("building","train_station")) 537 | (436,std::make_pair("building","storage_tank")) 538 | (437,std::make_pair("man_made","windmill")) 539 | (438,std::make_pair("shop","beauty")) 540 | (439,std::make_pair("building","semi")) 541 | (440,std::make_pair("highway","services")) 542 | (441,std::make_pair("bicycle","private")) 543 | (442,std::make_pair("route","ski")) 544 | (443,std::make_pair("service","emergency_access")) 545 | (444,std::make_pair("building","factory")) 546 | (445,std::make_pair("man_made","reinforced_slope")) 547 | (446,std::make_pair("amenity","car_sharing")) 548 | (447,std::make_pair("surface","earth")) 549 | (448,std::make_pair("shop","hifi")) 550 | (449,std::make_pair("amenity","car_rental")) 551 | (450,std::make_pair("barrier","hedge_bank")) 552 | (451,std::make_pair("shop","confectionery")) 553 | (452,std::make_pair("aeroway","terminal")) 554 | (453,std::make_pair("highway","passing_place")) 555 | (454,std::make_pair("building","building")) 556 | (455,std::make_pair("man_made","dyke")) 557 | (456,std::make_pair("building","construction")) 558 | (457,std::make_pair("building","shop")) 559 | (458,std::make_pair("natural","reef")) 560 | (459,std::make_pair("landuse","aquaculture")) 561 | (460,std::make_pair("shop","dry_cleaning")) 562 | (461,std::make_pair("amenity","embassy")) 563 | (462,std::make_pair("shop","newsagent")) 564 | (463,std::make_pair("landuse","salt_pond")) 565 | (464,std::make_pair("railway","spur")) 566 | (465,std::make_pair("wheelchair","unknown")) 567 | (466,std::make_pair("tourism","zoo")) 568 | (467,std::make_pair("man_made","waterway")) 569 | (468,std::make_pair("surface","fine_gravel")) 570 | (469,std::make_pair("shop","motorcycle")) 571 | (470,std::make_pair("building","Building")) 572 | (471,std::make_pair("railway","construction")) 573 | (472,std::make_pair("place","neighbourhood")) 574 | (473,std::make_pair("route","train")) 575 | (474,std::make_pair("building","no")) 576 | (475,std::make_pair("natural","mud")) 577 | (476,std::make_pair("place","region")) 578 | (477,std::make_pair("landuse","reservoir_watershed")) 579 | (478,std::make_pair("boundary","marker")) 580 | (479,std::make_pair("man_made","beacon")) 581 | (480,std::make_pair("shop","outdoor")) 582 | (481,std::make_pair("access","public")) 583 | (482,std::make_pair("abutters","industrial")) 584 | (483,std::make_pair("building","barn")) 585 | (484,std::make_pair("leisure","picnic_table")) 586 | (485,std::make_pair("building","hospital")) 587 | (486,std::make_pair("access","official")) 588 | (487,std::make_pair("shop","variety_store")) 589 | (488,std::make_pair("man_made","crane")) 590 | (489,std::make_pair("amenity","parking_fuel")) 591 | (490,std::make_pair("route","tram")) 592 | (491,std::make_pair("tourism","theme_park")) 593 | (492,std::make_pair("shop","pet")) 594 | (493,std::make_pair("building","kindergarten")) 595 | (494,std::make_pair("man_made","storage")) 596 | (495,std::make_pair("man_made","mast")) 597 | (496,std::make_pair("amenity","parking_entrance")) 598 | (497,std::make_pair("amenity","clock")) 599 | (498,std::make_pair("landuse","industrial_retail")) 600 | (499,std::make_pair("shop","video")) 601 | (500,std::make_pair("access","delivery")) 602 | (501,std::make_pair("amenity","driving_school")) 603 | (502,std::make_pair("service","yes")) 604 | (503,std::make_pair("natural","bare_rock")) 605 | (504,std::make_pair("building","chapel")) 606 | (505,std::make_pair("natural","volcano")) 607 | (506,std::make_pair("waterway","dock")) 608 | (507,std::make_pair("building","dormitory")) 609 | (508,std::make_pair("amenity","boat_storage")) 610 | (509,std::make_pair("man_made","tank")) 611 | (510,std::make_pair("man_made","flagpole")) 612 | (511,std::make_pair("surface","grass_paver")) 613 | (512,std::make_pair("shop","organic")) 614 | (513,std::make_pair("natural","landform")) 615 | (514,std::make_pair("highway","unsurfaced")) 616 | (515,std::make_pair("route","power")) 617 | (516,std::make_pair("surface","mud")) 618 | (517,std::make_pair("building","building_concrete")) 619 | (518,std::make_pair("abutters","retail")) 620 | (519,std::make_pair("building","store")) 621 | (520,std::make_pair("shop","vacant")) 622 | (521,std::make_pair("leisure","miniature_golf")) 623 | (522,std::make_pair("man_made","monitoring_station")) 624 | (523,std::make_pair("natural","waterfall")) 625 | (524,std::make_pair("aeroway","hangar")) 626 | (525,std::make_pair("shop","boutique")) 627 | (526,std::make_pair("route","detour")) 628 | (527,std::make_pair("building","way")) 629 | (528,std::make_pair("railway","stop")) 630 | (529,std::make_pair("amenity","ice_cream")) 631 | (530,std::make_pair("building","storage")) 632 | (531,std::make_pair("shop","car_parts")) 633 | (532,std::make_pair("natural","ridge")) 634 | (533,std::make_pair("shop","tyres")) 635 | (534,std::make_pair("railway","dismantled")) 636 | (535,std::make_pair("amenity","shop")) 637 | (536,std::make_pair("landuse","plant_nursery")) 638 | (537,std::make_pair("building","residentiel1")) 639 | (538,std::make_pair("barrier","field_boundary")) 640 | (539,std::make_pair("barrier","border_control")) 641 | (540,std::make_pair("surface","Paved")) 642 | (541,std::make_pair("barrier","sally_port")) 643 | (542,std::make_pair("amenity","bureau_de_change")) 644 | (543,std::make_pair("leisure","fishing")) 645 | (544,std::make_pair("amenity","charging_station")) 646 | (545,std::make_pair("building","supermarket")) 647 | (546,std::make_pair("highway","stile")) 648 | (547,std::make_pair("amenity","sauna")) 649 | (548,std::make_pair("place","municipality")) 650 | (549,std::make_pair("building","hotel")) 651 | (550,std::make_pair("surface","metal")) 652 | (551,std::make_pair("highway","incline_steep")) 653 | (552,std::make_pair("shop","estate_agent")) 654 | (553,std::make_pair("natural","grass")) 655 | (554,std::make_pair("shop","pharmacy")) 656 | (555,std::make_pair("surface","concrete_plates")) 657 | (556,std::make_pair("shop","copyshop")) 658 | (557,std::make_pair("surface","paving_stones_30")) 659 | (558,std::make_pair("surface","interlock")) 660 | (559,std::make_pair("access","hov")) 661 | (560,std::make_pair("highway","elevator")) 662 | (561,std::make_pair("boundary","local_authority")) 663 | (562,std::make_pair("man_made","communications_tower")) 664 | (563,std::make_pair("shop","deli")) 665 | (564,std::make_pair("barrier","turnstile")) 666 | (565,std::make_pair("building","offices")) 667 | (566,std::make_pair("building","bunker")) 668 | (567,std::make_pair("natural","stone")) 669 | (568,std::make_pair("railway","railway_crossing")) 670 | (569,std::make_pair("leisure","dog_park")) 671 | (570,std::make_pair("building","semi_detached")) 672 | (571,std::make_pair("man_made","watermill")) 673 | (572,std::make_pair("route","trolleybus")) 674 | (573,std::make_pair("admin_level","3")) 675 | (574,std::make_pair("building","block")) 676 | (575,std::make_pair("barrier","guard_rail")) 677 | (576,std::make_pair("bicycle","unknown")) 678 | (577,std::make_pair("highway","abandoned")) 679 | (578,std::make_pair("surface","dirt_sand")) 680 | (579,std::make_pair("barrier","chain")) 681 | (580,std::make_pair("barrier","bump_gate")) 682 | (581,std::make_pair("building","residental")) 683 | (582,std::make_pair("surface","cement")) 684 | (583,std::make_pair("man_made","embankment")) 685 | (584,std::make_pair("building","ruins")) 686 | (585,std::make_pair("highway","incline")) 687 | (586,std::make_pair("abutters","commercial")) 688 | (587,std::make_pair("barrier","hampshire_gate")) 689 | (588,std::make_pair("shop","music")) 690 | (589,std::make_pair("shop","funeral_directors")) 691 | (590,std::make_pair("wetland","mangrove")) 692 | (591,std::make_pair("place","borough")) 693 | (592,std::make_pair("building","apartment")) 694 | (593,std::make_pair("boundary","census")) 695 | (594,std::make_pair("barrier","kerb")) 696 | (595,std::make_pair("building","glasshouse")) 697 | (596,std::make_pair("aeroway","holding_position")) 698 | (597,std::make_pair("shop","general")) 699 | (598,std::make_pair("building","tank")) 700 | (599,std::make_pair("railway","monorail")) 701 | (600,std::make_pair("service","parking")) 702 | (601,std::make_pair("place","state")) 703 | (602,std::make_pair("railway","proposed")) 704 | (603,std::make_pair("shop","art")) 705 | (604,std::make_pair("natural","hill")) 706 | (605,std::make_pair("railway","turntable")) 707 | (606,std::make_pair("tourism","cabin")) 708 | (607,std::make_pair("shop","photo")) 709 | (608,std::make_pair("boundary","lot")) 710 | (609,std::make_pair("shop","fishmonger")) 711 | (610,std::make_pair("amenity","clinic")) 712 | (612,std::make_pair("boundary","political")) 713 | (613,std::make_pair("man_made","well")) 714 | (614,std::make_pair("highway","byway")) 715 | (615,std::make_pair("leisure","horse_riding")) 716 | (616,std::make_pair("service","bus")) 717 | (617,std::make_pair("building","tower")) 718 | (618,std::make_pair("entrance","service")) 719 | (619,std::make_pair("shop","fabric")) 720 | (620,std::make_pair("railway","miniature")) 721 | (621,std::make_pair("abutters","mixed")) 722 | (622,std::make_pair("surface","stone")) 723 | (623,std::make_pair("access","emergency")) 724 | (624,std::make_pair("landuse","mine")) 725 | (625,std::make_pair("amenity","shower")) 726 | (626,std::make_pair("waterway","lock")) 727 | (627,std::make_pair("area","yes")) 728 | ; 729 | 730 | boost::optional tag_from_name(name_type const& name) 731 | { 732 | boost::optional tag; 733 | tag_lookup_type::right_const_iterator right_iter = tag_lookup.right.find(name); 734 | if (right_iter != tag_lookup.right.end()) 735 | { 736 | tag.reset(right_iter->second); 737 | } 738 | return tag; 739 | } 740 | 741 | boost::optional name_from_tag(tag_type tag) 742 | { 743 | boost::optional name; 744 | tag_lookup_type::left_const_iterator left_iter = tag_lookup.left.find(tag); 745 | if (left_iter != tag_lookup.left.end()) 746 | { 747 | name.reset(left_iter->second); 748 | } 749 | return name; 750 | } 751 | 752 | boost::optional tag_index_from_kv(name_type const& key, std::string const& val) 753 | { 754 | boost::optional tag; 755 | tag_value_lookup_type::right_const_iterator right_iter = tag_value_lookup.right.find(std::make_pair(key,val)); 756 | if (right_iter != tag_value_lookup.right.end()) 757 | { 758 | tag.reset(right_iter->second); 759 | } 760 | else 761 | { 762 | tag_lookup_type::right_const_iterator iter = tag_lookup.right.find(key); 763 | if (iter != tag_lookup.right.end()) 764 | { 765 | tag.reset(1024 + iter->second); 766 | } 767 | } 768 | return tag; 769 | } 770 | 771 | boost::optional > kv_from_tag(tag_type tag) 772 | { 773 | boost::optional > kv; 774 | tag_value_lookup_type::left_const_iterator left_iter = tag_value_lookup.left.find(tag); 775 | if (left_iter != tag_value_lookup.left.end()) 776 | { 777 | kv.reset(left_iter->second); 778 | } 779 | return kv; 780 | } 781 | 782 | }} 783 | -------------------------------------------------------------------------------- /src/tags.hpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef MAPNIK_TAGS_HPP 24 | #define MAPNIK_TAGS_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace mapnik { namespace tags { 31 | typedef uint32_t tag_type; 32 | typedef std::string name_type; 33 | boost::optional tag_from_name(name_type const& name); 34 | boost::optional name_from_tag(tag_type tag); 35 | boost::optional tag_index_from_kv(name_type const& name, std::string const& val); 36 | boost::optional > kv_from_tag(tag_type tag); 37 | }} 38 | 39 | #endif // MAPNIK_TAGS_HPP 40 | -------------------------------------------------------------------------------- /src/vector_renderer.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | // mapnik 24 | #include 25 | #include "vector_renderer_impl.hpp" 26 | #include "opensciencemap_backend.hpp" 27 | #include "opensciencemap_backend_pbf.hpp" 28 | 29 | namespace mapnik 30 | { 31 | template class feature_style_processor >; 32 | template class vector_renderer; 33 | template class feature_style_processor >; 34 | template class vector_renderer; 35 | } 36 | -------------------------------------------------------------------------------- /src/vector_renderer.hpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef MAPNIK_VECTOR_RENDERER_HPP 24 | #define MAPNIK_VECTOR_RENDERER_HPP 25 | 26 | // mapnik 27 | #include // for MAPNIK_DECL 28 | #include 29 | #include // for noncopyable 30 | #include // for rule, symbolizers 31 | #include // for box2d 32 | #include // for CoordTransform 33 | 34 | // fwd declarations to speed up compile 35 | namespace mapnik { 36 | class Map; 37 | class feature_impl; 38 | class feature_type_style; 39 | class layer; 40 | class proj_transform; 41 | } 42 | 43 | namespace mapnik { 44 | 45 | template 46 | class MAPNIK_DECL vector_renderer : public feature_style_processor >, 47 | private mapnik::noncopyable 48 | { 49 | typedef T backend_type; 50 | public: 51 | typedef vector_renderer processor_impl_type; 52 | 53 | // ctor 54 | vector_renderer(Map const& m, backend_type & backend, double scale_factor=1.0); 55 | // dtor 56 | ~vector_renderer(); 57 | // hooks 58 | void start_map_processing(Map const& map); 59 | void end_map_processing(Map const& map); 60 | void start_layer_processing(layer const& lay, box2d const& query_extent); 61 | void end_layer_processing(layer const& lay); 62 | void start_style_processing(feature_type_style const& st); 63 | void end_style_processing(feature_type_style const& st); 64 | // impl 65 | void process(line_symbolizer const& sym, 66 | mapnik::feature_impl & feature, 67 | proj_transform const& prj_trans); 68 | 69 | void process(polygon_symbolizer const& sym, 70 | mapnik::feature_impl & feature, 71 | proj_transform const& prj_trans); 72 | 73 | void process(point_symbolizer const& sym, 74 | mapnik::feature_impl & feature, 75 | proj_transform const& prj_trans); 76 | 77 | void painted(bool painted) {} 78 | inline bool process(rule::symbolizers const& /*syms*/, 79 | mapnik::feature_impl & /*feature*/, 80 | proj_transform const& /*prj_trans*/) 81 | { 82 | // agg renderer doesn't support processing of multiple symbolizers. 83 | return false; 84 | } 85 | 86 | inline eAttributeCollectionPolicy attribute_collection_policy() const 87 | { 88 | return COLLECT_ALL; 89 | } 90 | 91 | private: 92 | backend_type & backend_; 93 | unsigned width_; 94 | unsigned height_; 95 | double scale_factor_; 96 | CoordTransform t_; 97 | box2d query_extent_; 98 | }; 99 | 100 | } 101 | 102 | #endif // MAPNIK_VECTOR_RENDERER_HPP 103 | -------------------------------------------------------------------------------- /src/vector_renderer_impl.hpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | // mapnik 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "vector_renderer.hpp" 31 | 32 | // boost 33 | #include 34 | #include 35 | 36 | namespace mapnik 37 | { 38 | 39 | template 40 | vector_renderer::vector_renderer(Map const& m, 41 | T & backend, 42 | double scale_factor) 43 | : feature_style_processor >(m, scale_factor), 44 | backend_(backend), 45 | width_(m.width()), 46 | height_(m.height()), 47 | scale_factor_(scale_factor), 48 | t_(m.width(),m.height(),m.get_current_extent()) 49 | { 50 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: Scale=" << m.scale(); 51 | } 52 | 53 | template 54 | vector_renderer::~vector_renderer() {} 55 | 56 | template 57 | void vector_renderer::start_map_processing(Map const& map) 58 | { 59 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: Start map processing bbox=" << map.get_current_extent(); 60 | } 61 | 62 | template 63 | void vector_renderer::end_map_processing(Map const& ) 64 | { 65 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: End map processing"; 66 | } 67 | 68 | template 69 | void vector_renderer::start_layer_processing(layer const& lay, box2d const& query_extent) 70 | { 71 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: Start processing layer=" << lay.name() ; 72 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: -- datasource=" << lay.datasource().get(); 73 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: -- query_extent=" << query_extent; 74 | query_extent_ = query_extent; 75 | } 76 | 77 | template 78 | void vector_renderer::end_layer_processing(layer const&) 79 | { 80 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer: End layer processing"; 81 | } 82 | 83 | template 84 | void vector_renderer::start_style_processing(feature_type_style const& st) 85 | { 86 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer:start style processing"; 87 | } 88 | 89 | template 90 | void vector_renderer::end_style_processing(feature_type_style const& st) 91 | { 92 | MAPNIK_LOG_DEBUG(vector_renderer) << "vector_renderer:end style processing"; 93 | } 94 | 95 | template 96 | void vector_renderer::process(polygon_symbolizer const& sym, 97 | mapnik::feature_impl & feature, 98 | proj_transform const& prj_trans) 99 | { 100 | agg::trans_affine tr; 101 | evaluate_transform(tr, feature, sym.get_transform()); 102 | typedef boost::mpl::vector conv_types; 103 | vertex_converter, backend_type, polygon_symbolizer, 104 | CoordTransform, proj_transform, agg::trans_affine, conv_types> 105 | converter(query_extent_,backend_,sym,t_,prj_trans,tr,scale_factor_); 106 | 107 | if (prj_trans.equal() && sym.clip()) converter.template set(); //optional clip (default: true) 108 | converter.template set(); //always transform 109 | converter.template set(); 110 | if (sym.simplify_tolerance() > 0.0) converter.template set(); // optional simplify converter 111 | if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter 112 | 113 | backend_.start_tile_element(feature, Polygon); 114 | 115 | BOOST_FOREACH( geometry_type & geom, feature.paths()) 116 | { 117 | if (geom.size() > 2) 118 | { 119 | converter.apply(geom); 120 | } 121 | } 122 | 123 | backend_.stop_tile_element(); 124 | } 125 | 126 | template 127 | void vector_renderer::process(line_symbolizer const& sym, 128 | mapnik::feature_impl & feature, 129 | proj_transform const& prj_trans) 130 | { 131 | agg::trans_affine tr; 132 | evaluate_transform(tr, feature, sym.get_transform()); 133 | 134 | box2d clipping_extent = query_extent_; 135 | if (sym.clip()) 136 | { 137 | double padding = (double)(query_extent_.width()/width_); 138 | padding *= 4; 139 | if (fabs(sym.offset()) > 0) 140 | padding *= fabs(sym.offset()) * 1.2; 141 | double x0 = query_extent_.minx(); 142 | double y0 = query_extent_.miny(); 143 | double x1 = query_extent_.maxx(); 144 | double y1 = query_extent_.maxy(); 145 | clipping_extent.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding); 146 | } 147 | 148 | typedef boost::mpl::vector conv_types; 149 | vertex_converter, backend_type, line_symbolizer, 150 | CoordTransform, proj_transform, agg::trans_affine, conv_types> 151 | converter(clipping_extent,backend_,sym,t_,prj_trans,tr,scale_factor_); 152 | 153 | if (prj_trans.equal() && sym.clip()) converter.template set(); //optional clip (default: true) 154 | converter.template set(); //always transform 155 | converter.template set(); 156 | if (sym.simplify_tolerance() > 0.0) converter.template set(); // optional simplify converter 157 | if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter 158 | 159 | backend_.start_tile_element(feature,LineString); 160 | 161 | BOOST_FOREACH( geometry_type & geom, feature.paths()) 162 | { 163 | if (geom.size() > 1) 164 | { 165 | converter.apply(geom); 166 | } 167 | } 168 | 169 | backend_.stop_tile_element(); 170 | } 171 | 172 | 173 | template 174 | void vector_renderer::process(point_symbolizer const& sym, 175 | mapnik::feature_impl & feature, 176 | proj_transform const& prj_trans) 177 | { 178 | agg::trans_affine tr; 179 | evaluate_transform(tr, feature, sym.get_transform()); 180 | typedef boost::mpl::vector conv_types; 181 | vertex_converter, backend_type, point_symbolizer, 182 | CoordTransform, proj_transform, agg::trans_affine, conv_types> 183 | converter(query_extent_,backend_,sym,t_,prj_trans,tr,scale_factor_); 184 | 185 | 186 | converter.template set(); //always transform 187 | converter.template set(); 188 | 189 | backend_.start_tile_element(feature,Point); 190 | 191 | BOOST_FOREACH( geometry_type & geom, feature.paths()) 192 | { 193 | converter.apply(geom); 194 | } 195 | 196 | backend_.stop_tile_element(); 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/vector_server.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * This file is part of Mapnik (c++ mapping toolkit) 4 | * 5 | * Copyright (C) 2012 Artem Pavlenko 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | *****************************************************************************/ 22 | 23 | #include "vector_renderer.hpp" 24 | #include "opensciencemap_backend_pbf.hpp" 25 | // not currently used 26 | //#include "opensciencemap_backend.hpp" 27 | 28 | // node 29 | #include // for FatalException, NODE_MODULE 30 | #include // for Buffer 31 | #include // for ObjectWrap 32 | 33 | // node-mapnik 34 | #include "mapnik_map.hpp" 35 | 36 | // std 37 | #include 38 | #include 39 | 40 | // boost 41 | #include 42 | 43 | using namespace v8; 44 | 45 | struct render_state 46 | { 47 | Map * m; 48 | bool error; 49 | std::string error_message; 50 | std::string output; 51 | Persistent callback; 52 | }; 53 | 54 | // fwd decl 55 | void async_render(uv_work_t* req); 56 | void after_render(uv_work_t* req); 57 | 58 | Handle render(Arguments const& args) 59 | { 60 | HandleScope scope; 61 | 62 | if (args.Length() != 2) { 63 | return ThrowException(Exception::TypeError( 64 | String::New("requires at least two arguments, a renderable mapnik object, and a callback"))); 65 | } 66 | 67 | if (!args[0]->IsObject()) 68 | { 69 | return ThrowException(Exception::TypeError( 70 | String::New("First argument must be a Map object"))); 71 | } 72 | 73 | Local obj = args[0]->ToObject(); 74 | if (obj->IsNull() || obj->IsUndefined() || !Map::constructor->HasInstance(obj->ToObject())) 75 | { 76 | return ThrowException(Exception::TypeError( 77 | String::New("First argument must be a Map object"))); 78 | } 79 | 80 | if (!args[1]->IsFunction()) 81 | { 82 | return ThrowException(Exception::TypeError( 83 | String::New("Second argument must be a callback function"))); 84 | } 85 | 86 | Map* m = node::ObjectWrap::Unwrap(args[0]->ToObject()); 87 | if (m->active() != 0) 88 | { 89 | return ThrowException(Exception::TypeError( 90 | String::New("Use a map pool to avoid sharing map objects between concurrent rendering"))); 91 | } 92 | 93 | Local callback = Local::Cast(args[1]); 94 | render_state * state = new render_state(); 95 | state->m = m; 96 | state->error = false; 97 | state->callback = Persistent::New(callback); 98 | uv_work_t * req = new uv_work_t(); 99 | req->data = state; 100 | int status = uv_queue_work(uv_default_loop(),req, async_render, after_render); 101 | assert(status == 0); 102 | return Undefined(); 103 | } 104 | 105 | void async_render(uv_work_t* req) 106 | { 107 | render_state * state = static_cast(req->data); 108 | Map * map_ptr = state->m; 109 | try 110 | { 111 | std::string output; 112 | mapnik::opensciencemap_backend_pbf backend(output); 113 | mapnik::vector_renderer ren(*map_ptr->get(),backend); 114 | ren.apply(); 115 | uint32_t bytes = backend.output_vector_tile(); 116 | state->output = output.substr(0,bytes); 117 | } 118 | catch (std::exception const& ex) 119 | { 120 | state->error = true; 121 | state->error_message = std::string("error occured during rendering: ") + ex.what(); 122 | } 123 | } 124 | 125 | void after_render(uv_work_t* req) 126 | { 127 | HandleScope scope; 128 | render_state * state = static_cast(req->data); 129 | 130 | if (state->error) 131 | { 132 | Local err = Exception::Error(String::New(state->error_message.c_str())); 133 | const unsigned argc = 1; 134 | Local argv[argc] = { err }; 135 | TryCatch try_catch; 136 | state->callback->Call(Context::GetCurrent()->Global(), argc, argv); 137 | if (try_catch.HasCaught()) 138 | { 139 | node::FatalException(try_catch); 140 | } 141 | } 142 | else 143 | { 144 | const unsigned argc = 2; 145 | 146 | node::Buffer *buf = node::Buffer::New((char*)state->output.data(), state->output.size()); 147 | 148 | Local argv[argc] = { 149 | Local::New(Null()), 150 | Local::New(buf->handle_) 151 | }; 152 | 153 | TryCatch try_catch; 154 | state->callback->Call(Context::GetCurrent()->Global(), argc, argv); 155 | if (try_catch.HasCaught()) 156 | { 157 | node::FatalException(try_catch); 158 | } 159 | } 160 | 161 | state->callback.Dispose(); 162 | delete state; 163 | delete req; 164 | } 165 | 166 | void RegisterModule(Handle target) 167 | { 168 | target->Set(String::NewSymbol("render"), 169 | FunctionTemplate::New(render)->GetFunction()); 170 | } 171 | 172 | NODE_MODULE(node_vector_server, RegisterModule) 173 | -------------------------------------------------------------------------------- /test/check.sh: -------------------------------------------------------------------------------- 1 | node server.js osm_vectors.xml 8000 & PID=$!; sleep 2; wget http://localhost:8000/0/0/0.osmtile; python vector_tile.py 0.osmtile; kill $PID -------------------------------------------------------------------------------- /test/load.sh: -------------------------------------------------------------------------------- 1 | node server.js osm_vectors.xml 8000 & PID=$!; sleep 2; siege "http://localhost:8000/0/0/0.osmtile"; sleep 5; kill $PID -------------------------------------------------------------------------------- /tiles/10842.osmtile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artemp/vector-tile-server/fa37ed52c64db8259c508dbc8654fd477ee1545c/tiles/10842.osmtile -------------------------------------------------------------------------------- /tiles/43373.osmtile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artemp/vector-tile-server/fa37ed52c64db8259c508dbc8654fd477ee1545c/tiles/43373.osmtile -------------------------------------------------------------------------------- /tiles/5430.osmtile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artemp/vector-tile-server/fa37ed52c64db8259c508dbc8654fd477ee1545c/tiles/5430.osmtile -------------------------------------------------------------------------------- /tiles/test.osmtile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artemp/vector-tile-server/fa37ed52c64db8259c508dbc8654fd477ee1545c/tiles/test.osmtile -------------------------------------------------------------------------------- /vector_tile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | def signed(val): 6 | if val & ~0x7f == 0x80 : 7 | return val|~0x7f 8 | else: 9 | return val&0x7f 10 | 11 | class vector_tile: 12 | 13 | TAGS_MAX = 627 14 | TAGS_LIMIT = 1024 15 | 16 | def __init__(self, buf) : 17 | self.buf = buf 18 | self.pos = 0 19 | self.tags = {} 20 | self.ways = [] 21 | 22 | def decodeSize (self): 23 | self.pos += 4 24 | return self.buf[0] << 24 | self.buf[1] << 16 | self.buf[2] << 8 | self.buf[3] 25 | 26 | def decodeVarint32 (self): 27 | pos = self.pos 28 | #print>>sys.stderr,pos #"BUFFER=>",self.buf[pos],self.buf[pos+1],self.buf[pos+2],self.buf[pos+3],self.buf[pos+4] 29 | if signed(self.buf[pos]) >= 0: 30 | self.pos +=1 31 | return self.buf[pos] 32 | elif signed(self.buf[pos+1]) >= 0: 33 | self.pos +=2 34 | return (self.buf[pos] & 0x7f) | (self.buf[pos+1] << 7) 35 | elif signed(self.buf[pos+2]) >= 0: 36 | self.pos +=3 37 | return (self.buf[pos] & 0x7f) | (self.buf[pos + 1] & 0x7f) << 7 | (self.buf[pos + 2]) << 14 38 | elif signed(self.buf[pos+3]) >= 0: 39 | self.pos +=4 40 | return (self.buf[pos] & 0x7f) | (self.buf[pos + 1] & 0x7f) << 7 | (self.buf[pos + 2] & 0x7f) << 14 | (self.buf[pos + 3]) << 21 41 | 42 | result = (self.buf[pos] & 0x7f) | (self.buf[pos + 1] & 0x7f) << 7 | (self.buf[pos + 2] & 0x7f) << 14 | (self.buf[pos + 3] & 0x7f) << 21 | (self.buf[pos + 4]) << 28 43 | print "--------------------------------------OOOPS" 44 | read = 5 45 | pos += 4 46 | while buf[pos]<0 and read < 10: 47 | pos+=1 48 | read+=1 49 | 50 | self.pos += read 51 | return result 52 | 53 | def decodeShortArray(self, numTags): 54 | bytes = self.decodeVarint32() 55 | print>>sys.stderr, "BYTES=", bytes 56 | end = self.pos + bytes 57 | index = [] 58 | while self.pos < end : 59 | val = self.decodeVarint32() 60 | index.append(val) 61 | return index 62 | 63 | def decodeTileTags(self, tag, index): 64 | val = self.decodeString() 65 | print "key=",tag ," val=",val 66 | self.tags[tag]=val 67 | 68 | def decodeString(self): 69 | size = self.decodeVarint32() 70 | pos = self.pos 71 | self.pos += size 72 | return self.buf[pos:pos + size] 73 | 74 | def decodeTileElement(self, type, index): 75 | bytes = self.decodeVarint32() 76 | end = self.pos + bytes 77 | indexCount = 1 78 | coordCount = 0 79 | if (type == 13): 80 | coordCount = 2 81 | 82 | while self.pos < end: 83 | val = self.decodeVarint32() 84 | #print "VAL=",val 85 | if val==0: break 86 | tag = val >> 3; 87 | #print>>sys.stderr, "POS=", self.pos, "VAL=", val, "TAG=", tag 88 | if tag == 11 : #TAG_ELEM_TAGS 89 | print "TAG_ELEM_TAGS" 90 | self.decodeWayTags(index) 91 | elif tag == 1: # TAG_ELEM_NUM_INDICES 92 | print "TAG_ELEM_NUM_INDICES" 93 | indexCount = self.decodeVarint32(); 94 | print "INDEX Count = ",indexCount 95 | #sys.exit(1) 96 | elif tag == 12: # TAG_ELEM_INDEX 97 | print "TAG_ELEM_INDEX" 98 | print "indexCount=", indexCount 99 | index = self.decodeShortArray(indexCount) 100 | print "INDEX:",index 101 | for i in range(0,indexCount): 102 | length = index[i]*2 103 | coordCount += length 104 | index[i] = length 105 | if indexCount < len(index): 106 | index[indexCount] = -1 107 | elif tag == 13: # TAG_ELEM_COORDS 108 | print "TAG_ELEM_COORDS" 109 | count = self.decodeWayCoordinates(coordCount) 110 | print "COUNT=",count, " --- " , coordCount 111 | elif tag == 21: # TAG_ELEM_LAYER 112 | print "TAG_ELEM_LAYER" 113 | sys.exit(1) 114 | else: 115 | print>>sys.stderr,"Invalid type for element:", tag 116 | sys.exit(1) 117 | 118 | def decodeWayTags(self,index): 119 | bytes = self.decodeVarint32() 120 | end = self.pos + bytes 121 | while self.pos < end: 122 | tagNum = self.decodeVarint32() 123 | if tagNum < self.TAGS_MAX: 124 | print "TagNum=", tagNum 125 | else : 126 | tagNum -= self.TAGS_LIMIT 127 | print "TagNum(Local)=", index[tagNum], "val=", self.tags[tagNum] 128 | 129 | 130 | def decodeWayCoordinates(self, nodes ): 131 | bytes = self.decodeVarint32() 132 | print>>sys.stderr,"BYTES=",bytes," pos=",self.pos 133 | end = self.pos + bytes 134 | last_x = 0 135 | last_y = 0 136 | count = 0 137 | even = True 138 | scale = 4096/400.0 139 | way = [] 140 | while self.pos < end: 141 | val = self.decodeVarint32() 142 | val = ((val >> 1) ^ -(val & 1)) #zigzag 143 | count +=1 144 | if even : 145 | last_x += val 146 | even = False 147 | way.insert(count,last_y / scale); 148 | print>>sys.stderr, "X=", last_x 149 | else : 150 | last_y += val 151 | even = True 152 | way.insert(count,last_y / scale); 153 | print>>sys.stderr, "Y=", last_y 154 | print "TILE pos=",self.pos," end=", end 155 | self.ways.append(way); 156 | return count 157 | 158 | def parse(filename): 159 | f = open(filename) 160 | s = f.read() 161 | tile = vector_tile(bytearray(s)) 162 | print "content length: ", tile.decodeSize() 163 | val = tile.decodeVarint32() 164 | numTags = 0 165 | curTag = 0 166 | index = [] 167 | while tile.pos < len(s): 168 | tag = val >> 3 169 | print>>sys.stderr, "POS=", tile.pos, "VAL=", val, "TAG=", tag 170 | if tag == 1 : # TAG_TILE_NUM_TAGS 171 | numTags = tile.decodeVarint32() 172 | elif tag == 2 : # TAG_TILE_TAG_KEYS 173 | index = tile.decodeShortArray(numTags) 174 | print "INDEX:",index 175 | elif tag == 3 : # TAG_TILE_TAG_VALUES: 176 | tile.decodeTileTags(curTag,index); 177 | curTag += 1 178 | elif tag == 11 : # TAG_TILE_LINE 179 | print "======== TAG_TILE_LINE" 180 | tile.decodeTileElement(tag, index); 181 | elif tag == 12 : # TAG_TILE_POLY 182 | print "======== TAG_TILE_POLY" 183 | tile.decodeTileElement(tag, index); 184 | elif tag == 13 : # TAG_TILE_POINT 185 | print "======== TAG_TILE_POINT" 186 | tile.decodeTileElement(tag, index); 187 | else: 188 | print>>sys.stderr,"Invalid type for tile:", tag 189 | break 190 | if (tile.pos < len(s)): 191 | val = tile.decodeVarint32() 192 | 193 | if __name__ == "__main__": 194 | 195 | if len(sys.argv) != 2 : 196 | print>>sys.stderr, "Usage:", sys.argv[0], "" 197 | sys.exit(1) 198 | parse(sys.argv[1]) 199 | -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 28 | 29 | 30 | 31 |
32 | 33 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /zoom_scales.xml.inc: -------------------------------------------------------------------------------- 1 | 250000000000"> 2 | 500000000"> 3 | 200000000"> 4 | 200000000"> 5 | 100000000"> 6 | 100000000"> 7 | 50000000"> 8 | 50000000"> 9 | 25000000"> 10 | 25000000"> 11 | 12500000"> 12 | 12500000"> 13 | 6500000"> 14 | 6500000"> 15 | 3000000"> 16 | 3000000"> 17 | 1500000"> 18 | 1500000"> 19 | 750000"> 20 | 750000"> 21 | 400000"> 22 | 400000"> 23 | 200000"> 24 | 200000"> 25 | 100000"> 26 | 100000"> 27 | 50000"> 28 | 50000"> 29 | 25000"> 30 | 25000"> 31 | 12500"> 32 | 12500"> 33 | 5000"> 34 | 5000"> 35 | 2500"> 36 | 2500"> 37 | 1000"> 38 | --------------------------------------------------------------------------------