Add --cluster-maxzoom option (#75)

* Add `--cluster-maxzoom` option

* Add tests, update changelog

* Update manpage

* Update tests

---------

Co-authored-by: Aurele Nitoref <aurele.nitoref@icloud.com>
This commit is contained in:
Erica Fischer
2023-02-24 16:05:45 -08:00
committed by GitHub
co-authored by Aurele Nitoref
parent 3d714e32b0
commit 329dd86bfd
9 changed files with 2552 additions and 7 deletions
+3
View File
@@ -1,4 +1,7 @@
* Add --cluster-maxzoom option to limit zoom levels that receive clustering
* Add `point_count_abbreviated` attribute to clustered features, for consistency with supercluster
* Makefile changes to support FreeBSD
* Add -r option to tile-join to provide a file containing a list of input files
## 2.23.0
+1 -1
View File
@@ -15,7 +15,7 @@ RELEASE_FLAGS := -O3 -DNDEBUG
DEBUG_FLAGS := -O0 -DDEBUG -fno-inline-functions -fno-omit-frame-pointer
OS := $(shell uname -o)
OS := $(shell uname -s)
ifeq ($(OS),FreeBSD)
ADVSHELL = /usr/local/bin/bash
else
+2
View File
@@ -456,6 +456,8 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
* `-al` or `--drop-lines`: Let "dot" dropping at lower zooms apply to lines too
* `-ap` or `--drop-polygons`: Let "dot" dropping at lower zooms apply to polygons too
* `-K` _distance_ or `--cluster-distance=`_distance_: Cluster points (as with `--cluster-densest-as-needed`, but without the experimental discovery process) that are approximately within _distance_ of each other. The units are tile coordinates within a nominally 256-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 10 are probably appropriate for typical marker sizes. See `--cluster-densest-as-needed` below for behavior.
* `-k` _zoom_ or `--cluster-maxzoom=`_zoom_: Max zoom on which to cluster points if clustering is enabled.
* `-kg` or `--cluster-maxzoom=g`: Set `--cluster-maxzoom=` to `maxzoom - 1` so that all features are visible at the maximum zoom level.
### Dropping a fraction of features to keep under tile size limits
+21 -4
View File
@@ -82,6 +82,7 @@ size_t max_tile_size = 500000;
size_t max_tile_features = 200000;
int cluster_distance = 0;
int tiny_polygon_size = 2;
int cluster_maxzoom = MAX_ZOOM;
long justx = -1, justy = -1;
std::string attribute_for_id = "";
size_t limit_tile_feature_count = 0;
@@ -1163,7 +1164,7 @@ void choose_first_zoom(long long *file_bbox, std::vector<struct reader> &readers
}
}
std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set<std::string> *exclude, std::set<std::string> *include, int exclude_all, json_object *filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, std::map<std::string, int> const *attribute_types, const char *pgm, std::map<std::string, attribute_op> const *attribute_accum, std::map<std::string, std::string> const &attribute_descriptions, std::string const &commandline, int minimum_maxzoom) {
std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set<std::string> *exclude, std::set<std::string> *include, int exclude_all, json_object *filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, bool guess_cluster_maxzoom, std::map<std::string, int> const *attribute_types, const char *pgm, std::map<std::string, attribute_op> const *attribute_accum, std::map<std::string, std::string> const &attribute_descriptions, std::string const &commandline, int minimum_maxzoom) {
int ret = EXIT_SUCCESS;
std::vector<struct reader> readers;
@@ -2102,7 +2103,7 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
}
bool changed = false;
while (maxzoom < 32 - full_detail && maxzoom < 33 - low_detail && cluster_distance > 0) {
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);
if (avg > zoom_mingap) {
break;
@@ -2112,7 +2113,7 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
changed = true;
}
if (changed) {
printf("Choosing a maxzoom of -z%d to keep most features distinct with cluster distance %d\n", maxzoom, cluster_distance);
printf("Choosing a maxzoom of -z%d to keep most features distinct with cluster distance %d and cluster maxzoom %d\n", maxzoom, cluster_distance, cluster_maxzoom);
}
if (droprate == -3) {
@@ -2203,6 +2204,11 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
}
}
if (cluster_maxzoom >= maxzoom && guess_cluster_maxzoom) {
cluster_maxzoom = maxzoom - 1;
fprintf(stderr, "Choosing a cluster maxzoom of -k%d to make all features visible at maximum zoom %d\n", cluster_maxzoom, maxzoom);
}
if (basezoom < 0 || droprate < 0) {
struct tile {
unsigned x;
@@ -2692,6 +2698,7 @@ int main(int argc, char **argv) {
const char *postfilter = NULL;
bool guess_maxzoom = false;
int minimum_maxzoom = 0;
bool guess_cluster_maxzoom = false;
std::set<std::string> exclude, include;
std::map<std::string, int> attribute_types;
@@ -2770,6 +2777,7 @@ int main(int argc, char **argv) {
{"drop-lines", no_argument, &additional[A_LINE_DROP], 1},
{"drop-polygons", no_argument, &additional[A_POLYGON_DROP], 1},
{"cluster-distance", required_argument, 0, 'K'},
{"cluster-maxzoom", required_argument, 0, 'k'},
{"Dropping or merging a fraction of features to keep under tile size limits", 0, 0, 0},
{"drop-densest-as-needed", no_argument, &additional[A_DROP_DENSEST_AS_NEEDED], 1},
@@ -3073,6 +3081,15 @@ int main(int argc, char **argv) {
}
break;
case 'k':
if (strcmp(optarg, "g") == 0) {
cluster_maxzoom = MAX_ZOOM - 1;
guess_cluster_maxzoom = true;
} else {
cluster_maxzoom = atoi_require(optarg, "Cluster maxzoom");
}
break;
case 'd':
full_detail = atoi_require(optarg, "Full detail");
if (full_detail > 30) {
@@ -3484,7 +3501,7 @@ int main(int argc, char **argv) {
auto input_ret = read_input(sources, name ? name : out_mbtiles ? out_mbtiles
: out_dir,
maxzoom, minzoom, basezoom, basezoom_marker_width, outdb, out_dir, &exclude, &include, exclude_all, filter, droprate, buffer, tmpdir, gamma, read_parallel, forcetable, attribution, gamma != 0, file_bbox, prefilter, postfilter, description, guess_maxzoom, &attribute_types, argv[0], &attribute_accum, attribute_descriptions, commandline, minimum_maxzoom);
maxzoom, minzoom, basezoom, basezoom_marker_width, outdb, out_dir, &exclude, &include, exclude_all, filter, droprate, buffer, tmpdir, gamma, read_parallel, forcetable, attribution, gamma != 0, file_bbox, prefilter, postfilter, description, guess_maxzoom, guess_cluster_maxzoom, &attribute_types, argv[0], &attribute_accum, attribute_descriptions, commandline, minimum_maxzoom);
ret = std::get<0>(input_ret);
+1
View File
@@ -53,6 +53,7 @@ extern size_t memsize;
extern size_t max_tile_size;
extern size_t max_tile_features;
extern int cluster_distance;
extern int cluster_maxzoom;
extern std::string attribute_for_id;
extern int tiny_polygon_size;
extern size_t limit_tile_feature_count;
+7 -1
View File
@@ -395,7 +395,7 @@ Parallel processing will also be automatic if the input file is in FlatGeobuf fo
.IP \(bu 2
\fB\fC\-zg\fR or \fB\fC\-\-maximum\-zoom=g\fR: Guess what is probably a reasonable maxzoom based on the spacing of features.
.IP \(bu 2
\fB\fC\-\-smallest\-maximum\-zoom\-guess=\fR\fIzoom\fP: Guess what is probably a reasonable maxzoom based on the spacing of features, but using the specified \fIzoom\fP if a lower maxzoom is guessed.
\fB\fC\-\-smallest\-maximum\-zoom\-guess=\fR\fIzoom\fP: Guess what is probably a reasonable maxzoom based on the spacing of features, but using the specified \fIzoom\fP if a lower maxzoom is guessed. If \fB\fC\-Bg\fR is also set, the base zoom will be set to the guessed maxzoom, with all the points carried forward into additional zooms through the one specified.
.IP \(bu 2
\fB\fC\-Z\fR \fIzoom\fP or \fB\fC\-\-minimum\-zoom=\fR\fIzoom\fP: Minzoom: the lowest zoom level for which tiles are generated (default 0)
.IP \(bu 2
@@ -573,6 +573,10 @@ preference to retaining points in sparse areas and dropping points in dense area
\fB\fC\-ap\fR or \fB\fC\-\-drop\-polygons\fR: Let "dot" dropping at lower zooms apply to polygons too
.IP \(bu 2
\fB\fC\-K\fR \fIdistance\fP or \fB\fC\-\-cluster\-distance=\fR\fIdistance\fP: Cluster points (as with \fB\fC\-\-cluster\-densest\-as\-needed\fR, but without the experimental discovery process) that are approximately within \fIdistance\fP of each other. The units are tile coordinates within a nominally 256\-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 10 are probably appropriate for typical marker sizes. See \fB\fC\-\-cluster\-densest\-as\-needed\fR below for behavior.
.IP \(bu 2
\fB\fC\-k\fR \fIzoom\fP or \fB\fC\-\-cluster\-maxzoom=\fR\fIzoom\fP: Max zoom on which to cluster points if clustering is enabled.
.IP \(bu 2
\fB\fC\-kg\fR or \fB\fC\-\-cluster\-maxzoom=g\fR: Set \fB\fC\-\-cluster\-maxzoom=\fR to \fB\fCmaxzoom \- 1\fR so that all features are visible at the maximum zoom level.
.RE
.SS Dropping a fraction of features to keep under tile size limits
.RS
@@ -952,6 +956,8 @@ The options are:
\fB\fC\-e\fR \fIdirectory\fP or \fB\fC\-\-output\-to\-directory=\fR\fIdirectory\fP: Write the new tiles to the specified directory instead of to an mbtiles file.
.IP \(bu 2
\fB\fC\-f\fR or \fB\fC\-\-force\fR: Remove \fIout.mbtiles\fP if it already exists.
.IP \(bu 2
\fB\fC\-r\fR or \fB\fC\-\-read\-from\fR: list of input mbtiles to read from.
.RE
.SS Tileset description and attribution
.RS
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2088,7 +2088,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
// representative of the other features in the tile.
const size_t MAX_INDICES = 100000;
if (additional[A_CLUSTER_DENSEST_AS_NEEDED] || cluster_distance != 0) {
if (z <= cluster_maxzoom && (additional[A_CLUSTER_DENSEST_AS_NEEDED] || cluster_distance != 0)) {
if (indices.size() < MAX_INDICES) {
indices.push_back(sf.index);
}