From 7f8eb4de83b21183e631be360f8d4bd77f335bd2 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Tue, 15 Dec 2015 15:52:08 -0800 Subject: [PATCH] Add an option to guess an appropriately dense base zoom level --- CHANGELOG.md | 5 +++ README.md | 3 +- geojson.c | 83 +++++++++++++++++++++++++++++++++++++++++++++--- man/tippecanoe.1 | 3 +- version.h | 2 +- 5 files changed, 89 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10e4a5d..0b13258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.5.0 + +* Base zoom for dot-dropping can be specified independently of + maxzoom for tiling + ## 1.4.3 * Encode numeric attributes as integers instead of floating point if possible diff --git a/README.md b/README.md index 04f86e3..71b7d77 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,8 @@ Options * -z _zoom_: Maxzoom: the highest zoom level for which tiles are generated (default 14) * -Z _zoom_: Minzoom: the lowest zoom level for which tiles are generated (default 0) - * -B _zoom_: Base zoom, the level at and above which all points are included in the tiles (default maxzoom) + * -B _zoom_: Base zoom, the level at and above which all points are included in the tiles (default maxzoom). + If you use -Bg, it will guess a zoom level that will keep less than 50,000 features in the densest tile. * -d _detail_: Detail at max zoom level (default 12, for tile resolution of 4096) * -D _detail_: Detail at lower zoom levels (default 12, for tile resolution of 4096) * -m _detail_: Minimum detail that it will try if tiles are too big at regular detail (default 7) diff --git a/geojson.c b/geojson.c index a9e43bf..17bb30d 100644 --- a/geojson.c +++ b/geojson.c @@ -1035,13 +1035,84 @@ int read_json(int argc, char **argv, char *fname, const char *layername, int max close(indexfd); } - /* Copy geometries to a new file in index order */ - indexfd = open(indexname, O_RDONLY); if (indexfd < 0) { perror("reopen sorted index"); exit(EXIT_FAILURE); } + + if (basezoom < 0) { + struct index *map = mmap(NULL, indexpos, PROT_READ, MAP_PRIVATE, indexfd, 0); + if (map == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + +#define MAX_ZOOM 30 + struct tile { + unsigned x; + unsigned y; + long long count; + } tile[MAX_ZOOM + 1], max[MAX_ZOOM + 1]; + + { + int i; + for (i = 0; i <= MAX_ZOOM; i++) { + tile[i].x = tile[i].y = tile[i].count = 0; + max[i].x = max[i].y = max[i].count = 0; + } + } + + long long indices = indexpos / sizeof(struct index); + long long i; + for (i = 0; i < indices; i++) { + unsigned xx, yy; + decode(map[i].index, &xx, &yy); + + int z; + for (z = 0; z <= MAX_ZOOM; z++) { + unsigned xxx = 0, yyy = 0; + if (z != 0) { + xxx = xx >> (32 - z); + yyy = yy >> (32 - z); + } + + if (tile[z].x != xxx || tile[z].y != yyy) { + if (tile[z].count > max[z].count) { + max[z] = tile[z]; + } + + tile[z].x = xxx; + tile[z].y = yyy; + tile[z].count = 0; + } + + tile[z].count++; + } + } + + basezoom = MAX_ZOOM; + + int z; + for (z = MAX_ZOOM; z >= 0; z--) { + if (tile[z].count > max[z].count) { + max[z] = tile[z]; + } + + if (max[z].count < 50000) { + basezoom = z; + } + + // printf("%d/%u/%u %lld\n", z, max[z].x, max[z].y, max[z].count); + } + + fprintf(stderr, "Choosing a base zoom of -B%d to keep %lld features in tile %d/%u/%u.\n", basezoom, max[basezoom].count, basezoom, max[basezoom].x, max[basezoom].y); + + munmap(map, indexpos); + } + + /* Copy geometries to a new file in index order */ + struct index *index_map = mmap(NULL, indexpos, PROT_READ, MAP_PRIVATE, indexfd, 0); if (index_map == MAP_FAILED) { perror("mmap index"); @@ -1262,7 +1333,11 @@ int main(int argc, char **argv) { break; case 'B': - basezoom = atoi(optarg); + if (strcmp(optarg, "g") == 0) { + basezoom = -2; + } else { + basezoom = atoi(optarg); + } break; case 'd': @@ -1347,7 +1422,7 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - if (basezoom < 0) { + if (basezoom == -1) { basezoom = maxzoom; } diff --git a/man/tippecanoe.1 b/man/tippecanoe.1 index 8754e4b..6f677bd 100644 --- a/man/tippecanoe.1 +++ b/man/tippecanoe.1 @@ -75,7 +75,8 @@ specified, the files are all merged into the single named layer. .IP \(bu 2 \-Z \fIzoom\fP: Minzoom: the lowest zoom level for which tiles are generated (default 0) .IP \(bu 2 -\-B \fIzoom\fP: Base zoom, the level at and above which all points are included in the tiles (default maxzoom) +\-B \fIzoom\fP: Base zoom, the level at and above which all points are included in the tiles (default maxzoom). +If you use \-Bg, it will guess a zoom level that will keep less than 50,000 features in the densest tile. .IP \(bu 2 \-d \fIdetail\fP: Detail at max zoom level (default 12, for tile resolution of 4096) .IP \(bu 2 diff --git a/version.h b/version.h index 5adfc75..955f192 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define VERSION "tippecanoe v1.4.3\n" +#define VERSION "tippecanoe v1.5.0\n"