From 4632b15b47d3686cff682e3ba3f6af892c8428d4 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Thu, 14 Mar 2024 14:54:54 -0700 Subject: [PATCH] Eradicate more 32s --- enumerate.cpp | 4 ++- geobuf.cpp | 4 +-- geocsv.cpp | 2 +- geometry.cpp | 38 ++++++++++++++--------------- main.cpp | 66 +++++++++++++++++++++++++------------------------- plugin.cpp | 6 ++--- projection.cpp | 38 +++++++++++++++-------------- read_json.cpp | 2 +- 8 files changed, 82 insertions(+), 78 deletions(-) diff --git a/enumerate.cpp b/enumerate.cpp index 691e06ce..e96f27f2 100644 --- a/enumerate.cpp +++ b/enumerate.cpp @@ -4,6 +4,8 @@ #include #include "errors.hpp" +#define MAX_MAXZOOM 32 + void enumerate(char *fname) { sqlite3 *db; @@ -31,7 +33,7 @@ void enumerate(char *fname) { long long x = sqlite3_column_int(stmt, 1); long long y = sqlite3_column_int(stmt, 2); - if (zoom < 0 || zoom > 31) { + if (zoom < 0 || zoom > MAX_MAXZOOM) { fprintf(stderr, "Corrupt mbtiles file: impossible zoom level %lld\n", zoom); exit(EXIT_IMPOSSIBLE); } diff --git a/geobuf.cpp b/geobuf.cpp index b754eac2..66ed3fd0 100644 --- a/geobuf.cpp +++ b/geobuf.cpp @@ -101,7 +101,7 @@ drawvec readPoint(std::vector &coords, size_t dim, double e) { ensureDim(dim); long long x, y; - projection->project(coords[0] / e, coords[1] / e, 32, &x, &y); + projection->project(coords[0] / e, coords[1] / e, GLOBAL_DETAIL, &x, &y); drawvec dv; dv.push_back(draw(VT_MOVETO, x, y)); return dv; @@ -128,7 +128,7 @@ drawvec readLinePart(std::vector &coords, size_t dim, double e, size_ } long long x, y; - projection->project(p[0], p[1], 32, &x, &y); + projection->project(p[0], p[1], GLOBAL_DETAIL, &x, &y); if (i == start) { dv.push_back(draw(VT_MOVETO, x, y)); diff --git a/geocsv.cpp b/geocsv.cpp index 69f7d507..8702f1f8 100644 --- a/geocsv.cpp +++ b/geocsv.cpp @@ -85,7 +85,7 @@ void parse_geocsv(std::vector &sst, std::string fnam double lat = atof(line[latcol].c_str()); long long x, y; - projection->project(lon, lat, 32, &x, &y); + projection->project(lon, lat, GLOBAL_DETAIL, &x, &y); drawvec dv; dv.push_back(draw(VT_MOVETO, x, y)); diff --git a/geometry.cpp b/geometry.cpp index f8e4903c..34adff94 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -52,8 +52,8 @@ drawvec decode_geometry(const char **meta, int z, unsigned tx, unsigned ty, long long long wwy = wy; if (z != 0) { - wwx -= tx << (32 - z); - wwy -= ty << (32 - z); + wwx -= tx << (GLOBAL_DETAIL - z); + wwy -= ty << (GLOBAL_DETAIL - z); } bbox[0] = std::min(wwx, bbox[0]); @@ -170,7 +170,7 @@ void check_polygon(drawvec &geom) { drawvec reduce_tiny_poly(drawvec const &geom, int z, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area) { drawvec out; - const double pixel = (1LL << (32 - detail - z)) * (double) tiny_polygon_size; + const double pixel = (1LL << (GLOBAL_DETAIL - detail - z)) * (double) tiny_polygon_size; bool included_last_outer = false; *still_needs_simplification = false; @@ -264,7 +264,7 @@ drawvec reduce_tiny_poly(drawvec const &geom, int z, int detail, bool *still_nee int quick_check(const long long *bbox, int z, long long buffer) { long long min = 0; - long long area = 1LL << (32 - z); + long long area = 1LL << (GLOBAL_DETAIL - z); // bbox entirely within the tile proper if (bbox[0] > min && bbox[1] > min && bbox[2] < area && bbox[3] < area) { @@ -295,7 +295,7 @@ bool point_within_tile(long long x, long long y, int z) { // No adjustment for buffer, because the point must be // strictly within the tile to appear exactly once - long long area = 1LL << (32 - z); + long long area = 1LL << (GLOBAL_DETAIL - z); return x >= 0 && y >= 0 && x < area && y < area; } @@ -459,8 +459,8 @@ drawvec impose_tile_boundaries(const drawvec &geom, long long extent) { } drawvec simplify_lines(drawvec &geom, int z, int tx, int ty, int detail, bool mark_tile_bounds, double simplification, size_t retain, drawvec const &shared_nodes, struct node *shared_nodes_map, size_t nodepos) { - int res = 1 << (32 - detail - z); - long long area = 1LL << (32 - z); + int res = 1 << (GLOBAL_DETAIL - detail - z); + long long area = 1LL << (GLOBAL_DETAIL - z); for (size_t i = 0; i < geom.size(); i++) { if (geom[i].op == VT_MOVETO) { @@ -491,8 +491,8 @@ drawvec simplify_lines(drawvec &geom, int z, int tx, int ty, int detail, bool ma // offset to global draw d = geom[i]; if (z != 0) { - d.x += tx * (1LL << (32 - z)); - d.y += ty * (1LL << (32 - z)); + d.x += tx * (1LL << (GLOBAL_DETAIL - z)); + d.y += ty * (1LL << (GLOBAL_DETAIL - z)); } // to quadkey @@ -823,7 +823,7 @@ std::vector chop_polygon(std::vector &geoms) { drawvec stairstep(drawvec &geom, int z, int detail) { drawvec out; - double scale = 1 << (32 - detail - z); + double scale = 1 << (GLOBAL_DETAIL - detail - z); for (size_t i = 0; i < geom.size(); i++) { geom[i].x = std::round(geom[i].x / scale); @@ -900,8 +900,8 @@ drawvec stairstep(drawvec &geom, int z, int detail) { } for (size_t i = 0; i < out.size(); i++) { - out[i].x *= 1 << (32 - detail - z); - out[i].y *= 1 << (32 - detail - z); + out[i].x *= 1LL << (GLOBAL_DETAIL - detail - z); + out[i].y *= 1LL << (GLOBAL_DETAIL - detail - z); } return out; @@ -1277,7 +1277,7 @@ drawvec polygon_to_anchor(const drawvec &geom) { if (goodness <= 0) { double lon, lat; - tile2lonlat(d.x, d.y, 32, &lon, &lat); + tile2lonlat(d.x, d.y, GLOBAL_DETAIL, &lon, &lat); static std::atomic warned(0); if (warned++ < 10) { @@ -1308,13 +1308,13 @@ drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigne // upper left of tile in world coordinates long long tx1 = 0, ty1 = 0; // lower right of tile in world coordinates; - long long tx2 = 1LL << 32; // , ty2 = 1LL << 32; + long long tx2 = 1LL << GLOBAL_DETAIL; // , ty2 = 1LL << GLOBAL_DETAIL; if (z != 0) { - tx1 = (long long) tx << (32 - z); - ty1 = (long long) ty << (32 - z); + tx1 = (long long) tx << (GLOBAL_DETAIL - z); + ty1 = (long long) ty << (GLOBAL_DETAIL - z); - tx2 = (long long) (tx + 1) << (32 - z); - // ty2 = (long long) (ty + 1) << (32 - z); + tx2 = (long long) (tx + 1) << (GLOBAL_DETAIL - z); + // ty2 = (long long) (ty + 1) << (GLOBAL_DETAIL - z); } // upper left of feature in world coordinates @@ -1369,7 +1369,7 @@ drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigne out.push_back(draw(VT_MOVETO, x - tx1, y - ty1)); break; } else { - double tilesize = 1LL << (32 - z); + double tilesize = 1LL << (GLOBAL_DETAIL - z); double goodness_threshold = tilesize / 100; if (label_goodness(geom, x - tx1, y - ty1) > goodness_threshold) { out.push_back(draw(VT_MOVETO, x - tx1, y - ty1)); diff --git a/main.cpp b/main.cpp index 72c00780..2bac12e1 100644 --- a/main.cpp +++ b/main.cpp @@ -333,7 +333,7 @@ int calc_feature_minzoom(struct index *ix, struct drop_state *ds, int maxzoom, d if (preserve_point_density_threshold > 0) { for (ssize_t i = 0; i < feature_minzoom && i < maxzoom; i++) { - if (ix->ix - ds[i].previndex > ((1LL << (32 - i)) / preserve_point_density_threshold) * ((1LL << (32 - i)) / preserve_point_density_threshold)) { + if (ix->ix - ds[i].previndex > ((1LL << (GLOBAL_DETAIL - i)) / preserve_point_density_threshold) * ((1LL << (GLOBAL_DETAIL - i)) / preserve_point_density_threshold)) { feature_minzoom = i; for (ssize_t j = i; j <= maxzoom; j++) { @@ -1181,21 +1181,21 @@ void choose_first_zoom(long long *file_bbox, long long *file_bbox1, long long *f // bounding box is the whole world. if (file_bbox[0] < 0) { file_bbox[0] = 0; - file_bbox[2] = (1LL << 32) - 1; + file_bbox[2] = (1LL << GLOBAL_DETAIL) - 1; } - if (file_bbox[2] > (1LL << 32) - 1) { + if (file_bbox[2] > (1LL << GLOBAL_DETAIL) - 1) { file_bbox[0] = 0; - file_bbox[2] = (1LL << 32) - 1; + file_bbox[2] = (1LL << GLOBAL_DETAIL) - 1; } if (file_bbox[1] < 0) { file_bbox[1] = 0; } - if (file_bbox[3] > (1LL << 32) - 1) { - file_bbox[3] = (1LL << 32) - 1; + if (file_bbox[3] > (1LL << GLOBAL_DETAIL) - 1) { + file_bbox[3] = (1LL << GLOBAL_DETAIL) - 1; } for (ssize_t z = minzoom; z >= 0; z--) { - long long shift = 1LL << (32 - z); + long long shift = 1LL << (GLOBAL_DETAIL - z); long long left = (file_bbox[0] - buffer * shift / 256) / shift; long long top = (file_bbox[1] - buffer * shift / 256) / shift; @@ -2064,7 +2064,7 @@ std::pair read_input(std::vector &sources, char *fname, i #if 0 double lon, lat; - tile2lonlat(x, y, 32, &lon, &lat); + tile2lonlat(x, y, GLOBAL_DETAIL, &lon, &lat); printf("{\"type\":\"Feature\", \"properties\":{}, \"geometry\":{\"type\":\"Point\", \"coordinates\":[%f,%f]}}\n", lon, lat); #endif @@ -2357,11 +2357,11 @@ std::pair read_input(std::vector &sources, char *fname, i if (maxzoom < 0) { maxzoom = 0; } - if (maxzoom > 32 - full_detail) { - maxzoom = 32 - full_detail; + if (maxzoom > GLOBAL_DETAIL - full_detail) { + maxzoom = GLOBAL_DETAIL - full_detail; } - if (maxzoom > 33 - low_detail) { // that is, maxzoom - 1 > 32 - low_detail - maxzoom = 33 - low_detail; + if (maxzoom - 1 > GLOBAL_DETAIL - low_detail) { + maxzoom = GLOBAL_DETAIL + 1 - low_detail; } if (!quiet) { @@ -2374,8 +2374,8 @@ std::pair read_input(std::vector &sources, char *fname, i } bool changed = false; - while (maxzoom < 32 - full_detail && maxzoom < 33 - low_detail && maxzoom < cluster_maxzoom && cluster_distance > 0) { - unsigned long long zoom_mingap = ((1LL << (32 - maxzoom)) / 256 * cluster_distance) * ((1LL << (32 - maxzoom)) / 256 * cluster_distance); + while (maxzoom < GLOBAL_DETAIL - full_detail && maxzoom < GLOBAL_DETAIL + 1 - low_detail && maxzoom < cluster_maxzoom && cluster_distance > 0) { + unsigned long long zoom_mingap = ((1LL << (GLOBAL_DETAIL - maxzoom)) / 256 * cluster_distance) * ((1LL << (GLOBAL_DETAIL - maxzoom)) / 256 * cluster_distance); if (avg > zoom_mingap) { break; } @@ -2414,11 +2414,11 @@ std::pair read_input(std::vector &sources, char *fname, i if (mz < 0) { mz = 0; } - if (mz > 32 - full_detail) { - mz = 32 - full_detail; + if (mz > GLOBAL_DETAIL - full_detail) { + mz = GLOBAL_DETAIL - full_detail; } - if (mz > 33 - low_detail) { // that is, mz - 1 > 32 - low_detail - mz = 33 - low_detail; + if (mz - 1 > GLOBAL_DETAIL - low_detail) { + mz = GLOBAL_DETAIL + 1 - low_detail; } if (mz > maxzoom || count <= 0) { @@ -2431,7 +2431,7 @@ std::pair read_input(std::vector &sources, char *fname, i double total_tile_count = 0; for (int i = 1; i <= maxzoom; i++) { - double tile_count = ceil(area_sum / ((1LL << (32 - i)) * (1LL << (32 - i)))); + double tile_count = ceil(area_sum / ((1LL << (GLOBAL_DETAIL - i)) * (1LL << (GLOBAL_DETAIL - i)))); total_tile_count += tile_count; // 2M tiles is an arbitrary limit, chosen to make tiling jobs @@ -2797,8 +2797,8 @@ std::pair read_input(std::vector &sources, char *fname, i midlat = (maxlat + minlat) / 2; midlon = (maxlon + minlon) / 2; - tile2lonlat(file_bbox[0], file_bbox[1], 32, &minlon, &maxlat); - tile2lonlat(file_bbox[2], file_bbox[3], 32, &maxlon, &minlat); + tile2lonlat(file_bbox[0], file_bbox[1], GLOBAL_DETAIL, &minlon, &maxlat); + tile2lonlat(file_bbox[2], file_bbox[3], GLOBAL_DETAIL, &maxlon, &minlat); if (midlat < minlat) { midlat = minlat; @@ -2817,11 +2817,11 @@ std::pair read_input(std::vector &sources, char *fname, i double minlat2 = 0, minlon2 = 0, maxlat2 = 0, maxlon2 = 0; // choose whichever of the two calculated bboxes is narrower if (file_bbox2[2] - file_bbox2[0] < file_bbox1[2] - file_bbox1[0]) { - tile2lonlat(file_bbox2[0], file_bbox2[1], 32, &minlon2, &maxlat2); - tile2lonlat(file_bbox2[2], file_bbox2[3], 32, &maxlon2, &minlat2); + tile2lonlat(file_bbox2[0], file_bbox2[1], GLOBAL_DETAIL, &minlon2, &maxlat2); + tile2lonlat(file_bbox2[2], file_bbox2[3], GLOBAL_DETAIL, &maxlon2, &minlat2); } else { - tile2lonlat(file_bbox1[0], file_bbox1[1], 32, &minlon2, &maxlat2); - tile2lonlat(file_bbox1[2], file_bbox1[3], 32, &maxlon2, &minlat2); + tile2lonlat(file_bbox1[0], file_bbox1[1], GLOBAL_DETAIL, &minlon2, &maxlat2); + tile2lonlat(file_bbox1[2], file_bbox1[3], GLOBAL_DETAIL, &maxlon2, &minlat2); } std::map merged_lm = merge_layermaps(layermaps); @@ -3684,8 +3684,8 @@ int main(int argc, char **argv) { // the same no matter what order the projection and bounding box are // specified in for (auto &c : clipbboxes) { - projection->project(c.lon1, c.lat1, 32, &c.minx, &c.maxy); - projection->project(c.lon2, c.lat2, 32, &c.maxx, &c.miny); + projection->project(c.lon1, c.lat1, GLOBAL_DETAIL, &c.minx, &c.maxy); + projection->project(c.lon2, c.lat2, GLOBAL_DETAIL, &c.maxx, &c.miny); } if (max_tilestats_sample_values < max_tilestats_values) { @@ -3724,12 +3724,12 @@ int main(int argc, char **argv) { // This previously dropped the maxzoom rather than the detail when they were in conflict, // which proved to be annoying. if (!guess_maxzoom) { - if (maxzoom > 32 - full_detail) { - full_detail = 32 - maxzoom; + if (maxzoom > GLOBAL_DETAIL - full_detail) { + full_detail = GLOBAL_DETAIL - maxzoom; fprintf(stderr, "Highest supported detail with maxzoom %d is %d\n", maxzoom, full_detail); } - if (maxzoom > 33 - low_detail) { // that is, maxzoom - 1 > 32 - low_detail - low_detail = 33 - maxzoom; + if (maxzoom - 1 > GLOBAL_DETAIL - low_detail) { + low_detail = GLOBAL_DETAIL + 1 - maxzoom; fprintf(stderr, "Highest supported low detail with maxzoom %d is %d\n", maxzoom, low_detail); } } @@ -3757,12 +3757,12 @@ int main(int argc, char **argv) { if (extra_detail >= 0 || prevent[P_SIMPLIFY_SHARED_NODES] || additional[A_EXTEND_ZOOMS] || extend_zooms_max > 0) { geometry_scale = 0; } else { - geometry_scale = 32 - (full_detail + maxzoom); + geometry_scale = GLOBAL_DETAIL - (full_detail + maxzoom); if (geometry_scale < 0) { geometry_scale = 0; if (!guess_maxzoom) { // This shouldn't be able to happen any more. Can it still? - fprintf(stderr, "Full detail + maxzoom > 32, so you are asking for more detail than is available.\n"); + fprintf(stderr, "Full detail + maxzoom > %d, so you are asking for more detail than is available.\n", GLOBAL_DETAIL); } } } diff --git a/plugin.cpp b/plugin.cpp index 73b68282..c7ca0e59 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -198,7 +198,7 @@ std::vector parse_layers(int fd, int z, unsigned x, unsigned y, std:: // Scale and offset geometry from global to tile for (size_t i = 0; i < dv.size(); i++) { - long long scale = 1LL << (32 - z); + long long scale = 1LL << (GLOBAL_DETAIL - z); dv[i].x = std::round((dv[i].x - scale * x) * extent / (double) scale); dv[i].y = std::round((dv[i].y - scale * y) * extent / (double) scale); } @@ -385,8 +385,8 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std:: for (size_t i = 0; i < dv.size(); i++) { unsigned sx = 0, sy = 0; if (z != 0) { - sx = x << (32 - z); - sy = y << (32 - z); + sx = x << (GLOBAL_DETAIL - z); + sy = y << (GLOBAL_DETAIL - z); } dv[i].x = std::round(dv[i].x / scale) * scale - sx; dv[i].y = std::round(dv[i].y / scale) * scale - sy; diff --git a/projection.cpp b/projection.cpp index eb92b6df..e2262b17 100644 --- a/projection.cpp +++ b/projection.cpp @@ -7,6 +7,8 @@ #include "projection.hpp" #include "errors.hpp" +#define UINT_BITS 32 + unsigned long long (*encode_index)(unsigned int wx, unsigned int wy) = NULL; void (*decode_index)(unsigned long long index, unsigned *wx, unsigned *wy) = NULL; @@ -84,23 +86,23 @@ void epsg3857totile(double ix, double iy, int zoom, long long *x, long long *y) ix = 40000000.0; } - *x = std::round(ix * (1LL << 31) / 6378137.0 / M_PI + (1LL << 31)); - *y = std::round(((1LL << 32) - 1) - (iy * (1LL << 31) / 6378137.0 / M_PI + (1LL << 31))); + *x = std::round(ix * (1LL << (GLOBAL_DETAIL - 1)) / 6378137.0 / M_PI + (1LL << (GLOBAL_DETAIL - 1))); + *y = std::round(((1LL << GLOBAL_DETAIL) - 1) - (iy * (1LL << (GLOBAL_DETAIL - 1)) / 6378137.0 / M_PI + (1LL << (GLOBAL_DETAIL - 1)))); if (zoom != 0) { - *x = std::round((double) *x / (1LL << (32 - zoom))); - *y = std::round((double) *y / (1LL << (32 - zoom))); + *x = std::round((double) *x / (1LL << (GLOBAL_DETAIL - zoom))); + *y = std::round((double) *y / (1LL << (GLOBAL_DETAIL - zoom))); } } void tiletoepsg3857(long long ix, long long iy, int zoom, double *ox, double *oy) { if (zoom != 0) { - ix <<= (32 - zoom); - iy <<= (32 - zoom); + ix <<= (GLOBAL_DETAIL - zoom); + iy <<= (GLOBAL_DETAIL - zoom); } - *ox = (ix - (1LL << 31)) * M_PI * 6378137.0 / (1LL << 31); - *oy = ((1LL << 32) - 1 - iy - (1LL << 31)) * M_PI * 6378137.0 / (1LL << 31); + *ox = (ix - (1LL << (GLOBAL_DETAIL - 1))) * M_PI * 6378137.0 / (1LL << (GLOBAL_DETAIL - 1)); + *oy = ((1LL << GLOBAL_DETAIL) - 1 - iy - (1LL << (GLOBAL_DETAIL - 1))) * M_PI * 6378137.0 / (1LL << (GLOBAL_DETAIL - 1)); } // https://en.wikipedia.org/wiki/Hilbert_curve @@ -149,20 +151,20 @@ void hilbert_d2xy(unsigned long long n, unsigned long long d, unsigned *x, unsig } unsigned long long encode_hilbert(unsigned int wx, unsigned int wy) { - return hilbert_xy2d(1LL << 32, wx, wy); + return hilbert_xy2d(1LL << UINT_BITS, wx, wy); } void decode_hilbert(unsigned long long index, unsigned *wx, unsigned *wy) { - hilbert_d2xy(1LL << 32, index, wx, wy); + hilbert_d2xy(1LL << UINT_BITS, index, wx, wy); } unsigned long long encode_quadkey(unsigned int wx, unsigned int wy) { unsigned long long out = 0; int i; - for (i = 0; i < 32; i++) { - unsigned long long v = ((wx >> (32 - (i + 1))) & 1) << 1; - v |= (wy >> (32 - (i + 1))) & 1; + for (i = 0; i < UINT_BITS; i++) { + unsigned long long v = ((wx >> (UINT_BITS - (i + 1))) & 1) << 1; + v |= (wy >> (UINT_BITS - (i + 1))) & 1; v = v << (64 - 2 * (i + 1)); out |= v; @@ -180,9 +182,9 @@ void decode_quadkey(unsigned long long index, unsigned *wx, unsigned *wy) { for (size_t ix = 0; ix < 256; ix++) { size_t xx = 0, yy = 0; - for (size_t i = 0; i < 32; i++) { - xx |= ((ix >> (64 - 2 * (i + 1) + 1)) & 1) << (32 - (i + 1)); - yy |= ((ix >> (64 - 2 * (i + 1) + 0)) & 1) << (32 - (i + 1)); + for (size_t i = 0; i < UINT_BITS; i++) { + xx |= ((ix >> (64 - 2 * (i + 1) + 1)) & 1) << (UINT_BITS - (i + 1)); + yy |= ((ix >> (64 - 2 * (i + 1) + 0)) & 1) << (UINT_BITS - (i + 1)); } decodex[ix] = xx; @@ -201,11 +203,11 @@ void decode_quadkey(unsigned long long index, unsigned *wx, unsigned *wy) { } unsigned coordinate_to_encodable(long long coord) { - return (unsigned) (coord / (1LL << (GLOBAL_DETAIL - 32))); + return (unsigned) (coord / (1LL << (GLOBAL_DETAIL - UINT_BITS))); } long long decoded_to_coordinate(unsigned coord) { - return ((long long) coord) * (1LL << (GLOBAL_DETAIL - 32)); + return ((long long) coord) * (1LL << (GLOBAL_DETAIL - UINT_BITS)); } void set_projection_or_exit(const char *optarg) { diff --git a/read_json.cpp b/read_json.cpp index 45e13658..2ea28b75 100644 --- a/read_json.cpp +++ b/read_json.cpp @@ -79,7 +79,7 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna long long x, y; double lon = j->value.array.array[0]->value.number.number; double lat = j->value.array.array[1]->value.number.number; - projection->project(lon, lat, 32, &x, &y); + projection->project(lon, lat, GLOBAL_DETAIL, &x, &y); if (j->value.array.length > 2) { static int warned = 0;