diff --git a/clip.cpp b/clip.cpp index 4b11a3dd..83d9b947 100644 --- a/clip.cpp +++ b/clip.cpp @@ -69,7 +69,7 @@ drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long lon } drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &edge_nodes, bool prevent_simplify_shared_nodes) { - long long area = 1LL << (32 - z); + long long area = 1LL << (GLOBAL_DETAIL - z); long long clip_buffer = buffer * area / 256; return simple_clip_poly(geom, -clip_buffer, -clip_buffer, area + clip_buffer, area + clip_buffer, @@ -78,7 +78,7 @@ drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &edge_nodes, drawvec clip_point(drawvec &geom, int z, long long buffer) { long long min = 0; - long long area = 1LL << (32 - z); + long long area = 1LL << (GLOBAL_DETAIL - z); min -= buffer * area / 256; area += buffer * area / 256; @@ -100,7 +100,7 @@ drawvec clip_point(drawvec &geom, long long minx, long long miny, long long maxx drawvec clip_lines(drawvec &geom, int z, long long buffer) { long long min = 0; - long long area = 1LL << (32 - z); + long long area = 1LL << (GLOBAL_DETAIL - z); min -= buffer * area / 256; area += buffer * area / 256; @@ -294,7 +294,7 @@ drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip, bool try if (clip) { long long area = 0xFFFFFFFF; if (z != 0) { - area = 1LL << (32 - z); + area = 1LL << (GLOBAL_DETAIL - z); } long long clip_buffer = buffer * area / 256; @@ -383,15 +383,15 @@ drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip, bool try } void to_tile_scale(drawvec &geom, int z, int detail) { - if (32 - detail - z < 0) { + if (GLOBAL_DETAIL - detail - z < 0) { for (size_t i = 0; i < geom.size(); i++) { - geom[i].x = std::round((double) geom[i].x * (1LL << (-(32 - detail - z)))); - geom[i].y = std::round((double) geom[i].y * (1LL << (-(32 - detail - z)))); + geom[i].x = std::round((double) geom[i].x * (1LL << (-(GLOBAL_DETAIL - detail - z)))); + geom[i].y = std::round((double) geom[i].y * (1LL << (-(GLOBAL_DETAIL - detail - z)))); } } else { for (size_t i = 0; i < geom.size(); i++) { - geom[i].x = std::round((double) geom[i].x / (1LL << (32 - detail - z))); - geom[i].y = std::round((double) geom[i].y / (1LL << (32 - detail - z))); + geom[i].x = std::round((double) geom[i].x / (1LL << (GLOBAL_DETAIL - detail - z))); + geom[i].y = std::round((double) geom[i].y / (1LL << (GLOBAL_DETAIL - detail - z))); } } } @@ -400,8 +400,8 @@ drawvec from_tile_scale(drawvec const &geom, int z, int detail) { drawvec out; for (size_t i = 0; i < geom.size(); i++) { draw d = geom[i]; - d.x *= (1LL << (32 - detail - z)); - d.y *= (1LL << (32 - detail - z)); + d.x *= (1LL << (GLOBAL_DETAIL - detail - z)); + d.y *= (1LL << (GLOBAL_DETAIL - detail - z)); out.push_back(d); } return out; @@ -526,7 +526,7 @@ double get_area(const drawvec &geom, size_t i, size_t j) { // do not use the full precision, shift them nearer to the origin so // their product is more likely to be exactly representable as a double. // - // (In practice they are actually 34-bit integers: 32 bits for the + // (In practice they are actually (GLOBAL_DETAIL + 2)-bit integers: GLOBAL_DETAIL bits for the // Mercator world plane, plus another two bits so features can stick // off either the left or right side. But that is still too many bits // for the product to fit either in a 64-bit long long or in a @@ -931,7 +931,7 @@ std::string overzoom(const mvt_tile &tile, int oz, int ox, int oy, int nz, int n // Convert feature geometry to world coordinates - long long tilesize = 1LL << (32 - oz); // source tile size in world coordinates + long long tilesize = 1LL << (GLOBAL_DETAIL - oz); // source tile size in world coordinates draw ring_closure(0, 0, 0); bool sametile = (nz == oz && nx == ox && ny == oy && outlayer.extent >= layer.extent); @@ -953,7 +953,7 @@ std::string overzoom(const mvt_tile &tile, int oz, int ox, int oy, int nz, int n // 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 + long long outtilesize = 1LL << (GLOBAL_DETAIL - nz); // destination tile size in world coordinates for (auto &g : geom) { g.x -= nx * outtilesize; g.y -= ny * outtilesize; diff --git a/decode.cpp b/decode.cpp index dedb4053..948fe245 100644 --- a/decode.cpp +++ b/decode.cpp @@ -25,8 +25,10 @@ #include "pmtiles_file.hpp" #include "errors.hpp" +#define MAX_MAXZOOM 32 // should this be higher? + int minzoom = 0; -int maxzoom = 32; +int maxzoom = MAX_MAXZOOM; bool force = false; bool progress_time() { @@ -456,7 +458,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set co int tx = sqlite3_column_int(stmt, 2); int ty = sqlite3_column_int(stmt, 3); - if (tz < 0 || tz >= 32) { + if (tz < 0 || tz >= MAX_MAXZOOM) { fprintf(stderr, "Impossible zoom level %d in mbtiles\n", tz); exit(EXIT_IMPOSSIBLE); } diff --git a/flatgeobuf.cpp b/flatgeobuf.cpp index a011c3e0..8deb7700 100644 --- a/flatgeobuf.cpp +++ b/flatgeobuf.cpp @@ -45,7 +45,7 @@ drawvec readPoints(const FlatGeobuf::Geometry *geometry) { for (unsigned int i = 0; i < xy->size(); i+=2) { long long x, y; - projection->project(xy->Get(i), xy->Get(i+1), 32, &x, &y); + projection->project(xy->Get(i), xy->Get(i+1), GLOBAL_DETAIL, &x, &y); dv.push_back(draw(VT_MOVETO, x, y)); } return dv; @@ -59,7 +59,7 @@ drawvec readLinePart(const FlatGeobuf::Geometry *geometry) { for (unsigned int i = 0; i < xy->size(); i+=2) { long long x, y; - projection->project(xy->Get(i), xy->Get(i+1), 32, &x, &y); + projection->project(xy->Get(i), xy->Get(i+1), GLOBAL_DETAIL, &x, &y); if (i == 0 || (ends != NULL && current_end < ends->size() && i == ends->Get(current_end)*2)) { dv.push_back(draw(VT_MOVETO, x, y)); if (i > 0) current_end++; diff --git a/geometry.hpp b/geometry.hpp index f847afd1..cdc455e0 100644 --- a/geometry.hpp +++ b/geometry.hpp @@ -20,6 +20,8 @@ #define VT_LINETO 2 #define VT_CLOSEPATH 7 +#define GLOBAL_DETAIL 32 + // The bitfield is to make sizeof(draw) be 16 instead of 24 // at the cost, apparently, of a 0.7% increase in running time // for packing and unpacking. diff --git a/tile.cpp b/tile.cpp index 9d64123a..efd4dd4e 100644 --- a/tile.cpp +++ b/tile.cpp @@ -57,8 +57,6 @@ extern "C" { #define CMD_BITS 3 -// Offset coordinates to keep them positive -#define COORD_OFFSET (4LL << 32) #define SHIFT_RIGHT(a) ((long long) std::round((double) (a) / (1LL << geometry_scale))) #define XSTRINGIFY(s) STRINGIFY(s) @@ -449,7 +447,7 @@ static void rewrite(serial_feature const &osf, int z, int nextzoom, int maxzoom, int k; for (k = 0; k < 4; k++) { // Division instead of right-shift because coordinates can be negative - bbox2[k] = osf.bbox[k] / (1 << (32 - nextzoom - 8)); + bbox2[k] = osf.bbox[k] / (1 << (GLOBAL_DETAIL - nextzoom - 8)); } // Decrement the top and left edges so that any features that are // touching the edge can potentially be included in the adjacent tiles too. @@ -472,8 +470,8 @@ static void rewrite(serial_feature const &osf, int z, int nextzoom, int maxzoom, // Offset from tile coordinates back to world coordinates unsigned sx = 0, sy = 0; if (z != 0) { - sx = tx << (32 - z); - sy = ty << (32 - z); + sx = tx << (GLOBAL_DETAIL - z); + sy = ty << (GLOBAL_DETAIL - z); } drawvec geom2; @@ -543,7 +541,7 @@ struct simplification_worker_arg { // so that the area of the feature is still somehow represented static drawvec revive_polygon(drawvec &geom, double area, int z, int detail) { // From area in world coordinates to area in tile coordinates - long long divisor = 1LL << (32 - detail - z); + long long divisor = 1LL << (GLOBAL_DETAIL - detail - z); area /= divisor * divisor; if (area == 0) { @@ -613,7 +611,7 @@ static double simplify_feature(serial_feature *p, drawvec const &shared_nodes, n // it would leave something else within the same tile pixel. if (t == VT_LINE && !prevent[P_SIMPLIFY_SHARED_NODES]) { // continues to deduplicate to line_detail even if we have extra detail - geom = remove_noop(geom, t, 32 - z - line_detail); + geom = remove_noop(geom, t, GLOBAL_DETAIL - z - line_detail); } bool already_marked = false; @@ -918,26 +916,26 @@ static bool clip_to_tile(serial_feature &sf, int z, long long buffer) { int quick = quick_check(sf.bbox, z, buffer); if (z == 0) { - if (sf.bbox[0] <= (1LL << 32) * buffer / 256 || sf.bbox[2] >= (1LL << 32) - ((1LL << 32) * buffer / 256)) { + if (sf.bbox[0] <= (1LL << GLOBAL_DETAIL) * buffer / 256 || sf.bbox[2] >= (1LL << GLOBAL_DETAIL) - ((1LL << GLOBAL_DETAIL) * buffer / 256)) { // If the geometry extends off the edge of the world, concatenate on another copy // shifted by 360 degrees, and then make sure both copies get clipped down to size. size_t n = sf.geometry.size(); - if (sf.bbox[0] <= (1LL << 32) * buffer / 256) { + if (sf.bbox[0] <= (1LL << GLOBAL_DETAIL) * buffer / 256) { for (size_t i = 0; i < n; i++) { - sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x + (1LL << 32), sf.geometry[i].y)); + sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x + (1LL << GLOBAL_DETAIL), sf.geometry[i].y)); } } - if (sf.bbox[2] >= (1LL << 32) - ((1LL << 32) * buffer / 256)) { + if (sf.bbox[2] >= (1LL << GLOBAL_DETAIL) - ((1LL << GLOBAL_DETAIL) * buffer / 256)) { for (size_t i = 0; i < n; i++) { - sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x - (1LL << 32), sf.geometry[i].y)); + sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x - (1LL << GLOBAL_DETAIL), sf.geometry[i].y)); } } sf.bbox[0] = 0; - sf.bbox[2] = 1LL << 32; + sf.bbox[2] = 1LL << GLOBAL_DETAIL; quick = -1; } @@ -1250,7 +1248,7 @@ void *run_prefilter(void *v) { } mvt_layer tmp_layer; - tmp_layer.extent = 1LL << 32; + tmp_layer.extent = 1LL << GLOBAL_DETAIL; tmp_layer.name = (*(rpa->layer_unmaps))[sf.segment][sf.layer]; if (sf.t == VT_POLYGON) { @@ -1267,8 +1265,8 @@ void *run_prefilter(void *v) { // Offset from tile coordinates back to world coordinates unsigned sx = 0, sy = 0; if (rpa->z != 0) { - sx = rpa->tx << (32 - rpa->z); - sy = rpa->ty << (32 - rpa->z); + sx = rpa->tx << (GLOBAL_DETAIL - rpa->z); + sy = rpa->ty << (GLOBAL_DETAIL - rpa->z); } for (size_t i = 0; i < tmp_feature.geometry.size(); i++) { tmp_feature.geometry[i].x += sx; @@ -1406,12 +1404,12 @@ static bool line_is_too_small(drawvec const &geometry, int z, int detail) { return true; } - long long x = std::round((double) geometry[0].x / (1LL << (32 - detail - z))); - long long y = std::round((double) geometry[0].y / (1LL << (32 - detail - z))); + long long x = std::round((double) geometry[0].x / (1LL << (GLOBAL_DETAIL - detail - z))); + long long y = std::round((double) geometry[0].y / (1LL << (GLOBAL_DETAIL - detail - z))); for (auto &g : geometry) { - long long xx = std::round((double) g.x / (1LL << (32 - detail - z))); - long long yy = std::round((double) g.y / (1LL << (32 - detail - z))); + long long xx = std::round((double) g.x / (1LL << (GLOBAL_DETAIL - detail - z))); + long long yy = std::round((double) g.y / (1LL << (GLOBAL_DETAIL - detail - z))); if (xx != x || yy != y) { return false; @@ -2194,7 +2192,7 @@ long long write_tile(decompressor *geoms, std::atomic *geompos_in, ch layer_features[x].geometry = remove_noop(layer_features[x].geometry, layer_features[x].t, 0); if (!(prevent[P_SIMPLIFY] || (z == maxzoom && prevent[P_SIMPLIFY_LOW]))) { // XXX revisit: why does this not take zoom into account? - layer_features[x].geometry = simplify_lines(layer_features[x].geometry, 32, 0, 0, 0, + layer_features[x].geometry = simplify_lines(layer_features[x].geometry, GLOBAL_DETAIL, 0, 0, 0, !(prevent[P_CLIPPING] || prevent[P_DUPLICATION]), simplification, layer_features[x].t == VT_POLYGON ? 4 : 0, shared_nodes, NULL, 0); } } @@ -2633,8 +2631,10 @@ exit(EXIT_IMPOSSIBLE); *arg->midy = y; *arg->most = len; } else if (len == *arg->most) { - unsigned long long a = (((unsigned long long) x) << 32) | y; - unsigned long long b = (((unsigned long long) *arg->midx) << 32) | *arg->midy; + // the details of the construction of a and b don't really matter very much; + // this is just a tie breaker if two maxzoom tiles have identical sizes + unsigned long long a = (((unsigned long long) x) << (8 * sizeof(y))) | y; + unsigned long long b = (((unsigned long long) *arg->midx) << (8 * sizeof(y))) | *arg->midy; if (a < b) { *arg->midx = x; @@ -2820,7 +2820,7 @@ int traverse_zooms(int *geomfd, off_t *geom_size, char *global_stringpool, std:: int err = INT_MAX; double zoom_gamma = gamma; - unsigned long long zoom_mingap = ((1LL << (32 - z)) / 256 * cluster_distance) * ((1LL << (32 - z)) / 256 * cluster_distance); + unsigned long long zoom_mingap = ((1LL << (GLOBAL_DETAIL - z)) / 256 * cluster_distance) * ((1LL << (GLOBAL_DETAIL - z)) / 256 * cluster_distance); long long zoom_minextent = 0; unsigned long long zoom_mindrop_sequence = 0; size_t zoom_tile_size = 0; diff --git a/write_json.cpp b/write_json.cpp index 307428e9..bdf1e852 100644 --- a/write_json.cpp +++ b/write_json.cpp @@ -389,12 +389,12 @@ void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y long long py = feat.geometry[g].y; if (op == VT_MOVETO || op == VT_LINETO) { - long long wscale = 1LL << (32 - z); + long long wscale = 1LL << (GLOBAL_DETAIL - z); long long wx = wscale * x + (wscale / layer.extent) * px; long long wy = wscale * y + (wscale / layer.extent) * py; double lat, lon; - projection->unproject(wx, wy, 32, &lon, &lat); + projection->unproject(wx, wy, GLOBAL_DETAIL, &lon, &lat); ops.push_back(lonlat(op, lon, lat, px, py)); } else {