diff --git a/README.md b/README.md index a308df8d..9dbbe7d2 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Options * -f: Delete the mbtiles file if it already exists instead of giving an error * -r rate: Rate at which dots are dropped at lower zoom levels (default 2.5) * -b pixels: Buffer size where features are duplicated from adjacent tiles (default 5) + * -g gamma: Rate at which especially dense dots are dropped (default 1, for no effect). A gamma of 2 reduces the number of dots duplicating the same pixel to the square root of their original number. Example ------- diff --git a/geojson.c b/geojson.c index ba11b217..0a0dbd43 100644 --- a/geojson.c +++ b/geojson.c @@ -893,7 +893,7 @@ int main(int argc, char **argv) { pool_init(&include, 0); int exclude_all = 0; - while ((i = getopt(argc, argv, "l:n:z:Z:d:D:o:x:y:r:b:fXt:")) != -1) { + while ((i = getopt(argc, argv, "l:n:z:Z:d:D:o:x:y:r:b:fXt:g:")) != -1) { switch (i) { case 'n': name = optarg; @@ -952,6 +952,10 @@ int main(int argc, char **argv) { tmpdir = optarg; break; + case 'g': + gamma = atof(optarg); + break; + default: fprintf(stderr, "Usage: %s -o out.mbtiles [-n name] [-l layername] [-z maxzoom] [-Z minzoom] [-d detail] [-D lower-detail] [-x excluded-field ...] [-y included-field ...] [-X] [-r droprate] [-b buffer] [-t tmpdir] [file.json]\n", argv[0]); exit(EXIT_FAILURE); diff --git a/tile.cc b/tile.cc index 0eb4fef1..a0c9b851 100644 --- a/tile.cc +++ b/tile.cc @@ -367,6 +367,10 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u interval = exp(log(droprate) * (basezoom - z)); } + unsigned long long previndex = 0; + double scale = (double) (1LL << (64 - 2 * (z + 8))); + double gap = 0; + std::vector features; int within[4] = { 0 }; @@ -496,6 +500,33 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u } else { continue; } + + unsigned long long index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2); + if (gap > 0) { + if (index == previndex) { + continue; // Exact duplicate: can't fulfil the gap requirement + } + + if (exp(log((index - previndex) / scale) * gamma) >= gap) { + // Dot is further from the previous than the nth root of the gap, + // so produce it, and choose a new gap at the next point. + gap = 0; + } else { + continue; + } + } else { + gap = (index - previndex) / scale; + + if (gap == 0) { + continue; // Exact duplicate: skip + } else if (gap < 1) { + continue; // Narrow dot spacing: need to stretch out + } else { + gap = 0; // Wider spacing than minimum: so pass through unchanged + } + } + + previndex = index; } bool reduced = false;