diff --git a/clip.cpp b/clip.cpp index 678f6808..b73b8449 100644 --- a/clip.cpp +++ b/clip.cpp @@ -5,6 +5,8 @@ #include #include "geometry.hpp" #include "errors.hpp" +#include "compression.hpp" +#include "mvt.hpp" drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) { drawvec out; @@ -565,3 +567,122 @@ drawvec close_poly(drawvec &geom) { return out; } + +std::string overzoom(std::string s, int oz, int ox, int oy, int nz, int nx, int ny, + int detail, int buffer, std::set const &keep) { + mvt_tile tile, outtile; + bool was_compressed; + + try { + if (!tile.decode(s, was_compressed)) { + fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", oz, ox, oy); + exit(EXIT_MVT); + } + } catch (std::exception const &e) { + fprintf(stderr, "PBF decoding error in tile %d/%u/%u\n", oz, ox, oy); + exit(EXIT_PROTOBUF); + } + + for (auto const &layer : tile.layers) { + mvt_layer outlayer = mvt_layer(); + + outlayer.name = layer.name; + outlayer.version = layer.version; + outlayer.extent = 1LL << detail; + + for (auto const &feature : layer.features) { + mvt_feature outfeature; + drawvec geom; + int t = feature.type; + + // Convert feature geometry to world coordinates + + long long tilesize = 1LL << (32 - oz); // source tile size in world coordinates + draw ring_closure(0, 0, 0); + + for (auto const &g : feature.geometry) { + if (g.op == mvt_closepath) { + geom.push_back(ring_closure); + } else { + geom.emplace_back(g.op, + g.x * tilesize / layer.extent + ox * tilesize, + g.y * tilesize / layer.extent + oy * tilesize); + + if (g.op == mvt_moveto) { + ring_closure = geom.back(); + ring_closure.op = mvt_lineto; + } + } + } + + // Now offset from world coordinates to output tile coordinates, + // but retain world scale, because that is what tippecanoe clipping expects + + long long outtilesize = 1LL << (32 - nz); // destination tile size in world coordinates + for (auto &g : geom) { + g.x -= nx * outtilesize; + g.y -= ny * outtilesize; + } + + // Clip to output tile + + if (t == VT_LINE) { + geom = clip_lines(geom, nz, buffer); + } else if (t == VT_POLYGON) { + geom = simple_clip_poly(geom, nz, buffer); + } else if (t == VT_POINT) { + geom = clip_point(geom, nz, buffer); + } + + // Scale to output tile extent + + to_tile_scale(geom, nz, detail); + + // Clean geometries + + geom = remove_noop(geom, t, 0); + if (t == VT_POLYGON) { + geom = clean_or_clip_poly(geom, 0, 0, false); + geom = close_poly(geom); + } + + // Add geometry to output feature + + outfeature.type = t; + for (auto const &g : geom) { + outfeature.geometry.emplace_back(g.op, g.x, g.y); + } + + // ID and attributes, if it didn't get clipped away + + if (outfeature.geometry.size() > 0) { + if (feature.has_id) { + outfeature.has_id = true; + outfeature.id = feature.id; + } + + for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) { + if (keep.size() == 0 || keep.find(layer.keys[feature.tags[i]]) != keep.end()) { + outlayer.tag(outfeature, layer.keys[feature.tags[i]], layer.values[feature.tags[i + 1]]); + } + } + + outlayer.features.push_back(outfeature); + } + } + + if (outlayer.features.size() > 0) { + outtile.layers.push_back(outlayer); + } + } + + if (outtile.layers.size() > 0) { + std::string pbf = outtile.encode(); + std::string compressed; + compress(pbf, compressed, true); + + return compressed; + } else { + return ""; + } +} diff --git a/geometry.hpp b/geometry.hpp index 50a86be1..79bfebec 100644 --- a/geometry.hpp +++ b/geometry.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -88,4 +89,7 @@ drawvec clip_point(drawvec &geom, long long x1, long long y1, long long x2, long void visvalingam(drawvec &ls, size_t start, size_t end, double threshold, size_t retain); int pnpoly(const drawvec &vert, size_t start, size_t nvert, long long testx, long long testy); +std::string overzoom(std::string s, int oz, int ox, int oy, int nz, int nx, int ny, + int detail, int buffer, std::set const &keep); + #endif diff --git a/overzoom.cpp b/overzoom.cpp index a4b18b83..43024f7e 100644 --- a/overzoom.cpp +++ b/overzoom.cpp @@ -15,124 +15,6 @@ int buffer = 5; // tippecanoe-style: mvt buffer == extent * buffer / 256; std::set keep; -std::string overzoom(std::string s, int oz, int ox, int oy, int nz, int nx, int ny) { - mvt_tile tile, outtile; - bool was_compressed; - - try { - if (!tile.decode(s, was_compressed)) { - fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", oz, ox, oy); - exit(EXIT_MVT); - } - } catch (std::exception const &e) { - fprintf(stderr, "PBF decoding error in tile %d/%u/%u\n", oz, ox, oy); - exit(EXIT_PROTOBUF); - } - - for (auto const &layer : tile.layers) { - mvt_layer outlayer = mvt_layer(); - - outlayer.name = layer.name; - outlayer.version = layer.version; - outlayer.extent = 1LL << detail; - - for (auto const &feature : layer.features) { - mvt_feature outfeature; - drawvec geom; - int t = feature.type; - - // Convert feature geometry to world coordinates - - long long tilesize = 1LL << (32 - oz); // source tile size in world coordinates - draw ring_closure(0, 0, 0); - - for (auto const &g : feature.geometry) { - if (g.op == mvt_closepath) { - geom.push_back(ring_closure); - } else { - geom.emplace_back(g.op, - g.x * tilesize / layer.extent + ox * tilesize, - g.y * tilesize / layer.extent + oy * tilesize); - - if (g.op == mvt_moveto) { - ring_closure = geom.back(); - ring_closure.op = mvt_lineto; - } - } - } - - // Now offset from world coordinates to output tile coordinates, - // but retain world scale, because that is what tippecanoe clipping expects - - long long outtilesize = 1LL << (32 - nz); // destination tile size in world coordinates - for (auto &g : geom) { - g.x -= nx * outtilesize; - g.y -= ny * outtilesize; - } - - // Clip to output tile - - if (t == VT_LINE) { - geom = clip_lines(geom, nz, buffer); - } else if (t == VT_POLYGON) { - geom = simple_clip_poly(geom, nz, buffer); - } else if (t == VT_POINT) { - geom = clip_point(geom, nz, buffer); - } - - // Scale to output tile extent - - to_tile_scale(geom, nz, detail); - - // Clean geometries - - geom = remove_noop(geom, t, 0); - if (t == VT_POLYGON) { - geom = clean_or_clip_poly(geom, 0, 0, false); - geom = close_poly(geom); - } - - // Add geometry to output feature - - outfeature.type = t; - for (auto const &g : geom) { - outfeature.geometry.emplace_back(g.op, g.x, g.y); - } - - // ID and attributes, if it didn't get clipped away - - if (outfeature.geometry.size() > 0) { - if (feature.has_id) { - outfeature.has_id = true; - outfeature.id = feature.id; - } - - for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) { - if (keep.size() == 0 || keep.find(layer.keys[feature.tags[i]]) != keep.end()) { - outlayer.tag(outfeature, layer.keys[feature.tags[i]], layer.values[feature.tags[i + 1]]); - } - } - - outlayer.features.push_back(outfeature); - } - } - - if (outlayer.features.size() > 0) { - outtile.layers.push_back(outlayer); - } - } - - if (outtile.layers.size() > 0) { - std::string pbf = outtile.encode(); - std::string compressed; - compress(pbf, compressed, true); - - return compressed; - } else { - return ""; - } -} - void usage(char **argv) { fprintf(stderr, "Usage: %s -o newtile.pbf.gz tile.pbf.gz oz/ox/oy nz/nx/ny\n", argv[0]); fprintf(stderr, "to create tile nz/nx/ny from tile oz/ox/oy\n"); @@ -209,7 +91,7 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - std::string out = overzoom(tile, oz, ox, oy, nz, nx, ny); + std::string out = overzoom(tile, oz, ox, oy, nz, nx, ny, detail, buffer, keep); fwrite(out.c_str(), sizeof(char), out.size(), f); fclose(f); diff --git a/tile-join.cpp b/tile-join.cpp index 8940d400..c1f74786 100644 --- a/tile-join.cpp +++ b/tile-join.cpp @@ -517,6 +517,22 @@ struct reader *begin_reading(char *fname) { return r; } +std::string retrieve_overzoom(struct reader *r, zxy tile) { + // lock around sqlite3 access + static pthread_mutex_t retrieve_lock; + std::string ret = ""; + + if (pthread_mutex_lock(&retrieve_lock) != 0) { + perror("pthread_mutex_lock"); + } + + if (pthread_mutex_unlock(&retrieve_lock) != 0) { + perror("pthread_mutex_unlock"); + } + + return ret; +} + struct arg { std::map> inputs{}; std::map outputs{}; @@ -548,6 +564,10 @@ void *join_worker(void *v) { // zoom level it did produce last. printf("overzooming %lld/%lld/%lld from zoom %d\n", ai->first.z, ai->first.x, ai->first.y, r->maxzoom_so_far); + std::string overzoomed = retrieve_overzoom(r, ai->first); + if (overzoomed.size() != 0) { + ai->second.push_back(overzoomed); + } } }