mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Add maximum pseudocluster size option for low-zoom points (#119)
* Trying to improve cluster positions * Fix centroid calculation * Just move points to cluster centroids; add point gap threshold * Add maximum-point-gap option * Fix formatting * Rename options for clarity; add tests; update changelog * Add missing break to switch * Revert unneeded constructor cleanup that broke a test somehow * Clean up comments * Remove unused --move-points-to-cluster-centroids * Mention tile-join change in changelog
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
# 2.28.0
|
||||||
|
|
||||||
|
* Add --preserve-point-density-threshold option to reduce blank areas of the map at low zooms
|
||||||
|
* Fix tile-join bug where use of --read-from would also accidentally enable --quiet
|
||||||
|
|
||||||
# 2.27.0
|
# 2.27.0
|
||||||
|
|
||||||
* Do more of line simplification in integer coordinates, to make behavior consistent across platforms
|
* Do more of line simplification in integer coordinates, to make behavior consistent across platforms
|
||||||
|
|||||||
@@ -461,6 +461,7 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
|
|||||||
* `-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` _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.
|
* `-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.
|
* `-kg` or `--cluster-maxzoom=g`: Set `--cluster-maxzoom=` to `maxzoom - 1` so that all features are visible at the maximum zoom level.
|
||||||
|
* `--preserve-point-density-threshold=`_level_: At the low zoom levels, do not reduce point density below the specified _level_, even if the specfied drop rate would normally call for it, so that low-density areas of the map do not appear blank. The unit is the distance between preserved points, as a fraction of the size of a tile. Values of 32 or 64 are probably appropriate for typical marker sizes.
|
||||||
|
|
||||||
### Dropping a fraction of features to keep under tile size limits
|
### Dropping a fraction of features to keep under tile size limits
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ size_t limit_tile_feature_count = 0;
|
|||||||
size_t limit_tile_feature_count_at_maxzoom = 0;
|
size_t limit_tile_feature_count_at_maxzoom = 0;
|
||||||
unsigned int drop_denser = 0;
|
unsigned int drop_denser = 0;
|
||||||
std::map<std::string, serial_val> set_attributes;
|
std::map<std::string, serial_val> set_attributes;
|
||||||
|
unsigned long long preserve_point_density_threshold = 0;
|
||||||
|
|
||||||
std::vector<order_field> order_by;
|
std::vector<order_field> order_by;
|
||||||
bool order_reverse;
|
bool order_reverse;
|
||||||
@@ -277,7 +278,7 @@ struct drop_state {
|
|||||||
double gap;
|
double gap;
|
||||||
unsigned long long previndex;
|
unsigned long long previndex;
|
||||||
double interval;
|
double interval;
|
||||||
double seq;
|
double seq; // floating point because interval is
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drop_densest {
|
struct drop_densest {
|
||||||
@@ -292,8 +293,6 @@ struct drop_densest {
|
|||||||
|
|
||||||
int calc_feature_minzoom(struct index *ix, struct drop_state *ds, int maxzoom, double gamma) {
|
int calc_feature_minzoom(struct index *ix, struct drop_state *ds, int maxzoom, double gamma) {
|
||||||
int feature_minzoom = 0;
|
int feature_minzoom = 0;
|
||||||
unsigned xx, yy;
|
|
||||||
decode_index(ix->ix, &xx, &yy);
|
|
||||||
|
|
||||||
if (gamma >= 0 && (ix->t == VT_POINT ||
|
if (gamma >= 0 && (ix->t == VT_POINT ||
|
||||||
(additional[A_LINE_DROP] && ix->t == VT_LINE) ||
|
(additional[A_LINE_DROP] && ix->t == VT_LINE) ||
|
||||||
@@ -301,12 +300,43 @@ int calc_feature_minzoom(struct index *ix, struct drop_state *ds, int maxzoom, d
|
|||||||
for (ssize_t i = maxzoom; i >= 0; i--) {
|
for (ssize_t i = maxzoom; i >= 0; i--) {
|
||||||
ds[i].seq++;
|
ds[i].seq++;
|
||||||
}
|
}
|
||||||
|
ssize_t chosen = maxzoom + 1;
|
||||||
for (ssize_t i = maxzoom; i >= 0; i--) {
|
for (ssize_t i = maxzoom; i >= 0; i--) {
|
||||||
if (ds[i].seq >= 0) {
|
if (ds[i].seq < 0) {
|
||||||
ds[i].seq -= ds[i].interval;
|
|
||||||
} else {
|
|
||||||
feature_minzoom = i + 1;
|
feature_minzoom = i + 1;
|
||||||
|
|
||||||
|
// The feature we are pushing out
|
||||||
|
// appears in zooms i + 1 through maxzoom,
|
||||||
|
// so track where that was so we can make sure
|
||||||
|
// not to cluster something else that is *too*
|
||||||
|
// far away into it.
|
||||||
|
for (ssize_t j = i + 1; j <= maxzoom; j++) {
|
||||||
|
ds[j].previndex = ix->ix;
|
||||||
|
}
|
||||||
|
|
||||||
|
chosen = i + 1;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
ds[i].seq -= ds[i].interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this feature has been chosen only for a high zoom level,
|
||||||
|
// check whether at a low zoom level it is nevertheless too far
|
||||||
|
// from the last feature chosen for that low zoom, in which case
|
||||||
|
// we will go ahead and push it out.
|
||||||
|
|
||||||
|
if (preserve_point_density_threshold > 0) {
|
||||||
|
for (ssize_t i = 0; i < chosen && i < maxzoom; i++) {
|
||||||
|
if (ix->ix - ds[i].previndex > ((1LL << (32 - i)) / preserve_point_density_threshold) * ((1LL << (32 - i)) / preserve_point_density_threshold)) {
|
||||||
|
feature_minzoom = i;
|
||||||
|
|
||||||
|
for (ssize_t j = i; j <= maxzoom; j++) {
|
||||||
|
ds[j].previndex = ix->ix;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2898,6 +2928,7 @@ int main(int argc, char **argv) {
|
|||||||
{"drop-polygons", no_argument, &additional[A_POLYGON_DROP], 1},
|
{"drop-polygons", no_argument, &additional[A_POLYGON_DROP], 1},
|
||||||
{"cluster-distance", required_argument, 0, 'K'},
|
{"cluster-distance", required_argument, 0, 'K'},
|
||||||
{"cluster-maxzoom", required_argument, 0, 'k'},
|
{"cluster-maxzoom", required_argument, 0, 'k'},
|
||||||
|
{"preserve-point-density-threshold", required_argument, 0, '~'},
|
||||||
|
|
||||||
{"Dropping or merging a fraction of features to keep under tile size limits", 0, 0, 0},
|
{"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},
|
{"drop-densest-as-needed", no_argument, &additional[A_DROP_DENSEST_AS_NEEDED], 1},
|
||||||
@@ -3105,6 +3136,8 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stderr, "%s: --drop-denser can be at most 100\n", argv[0]);
|
fprintf(stderr, "%s: --drop-denser can be at most 100\n", argv[0]);
|
||||||
exit(EXIT_ARGS);
|
exit(EXIT_ARGS);
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(opt, "preserve-point-density-threshold") == 0) {
|
||||||
|
preserve_point_density_threshold = atoll_require(optarg, "Preserve point density threshold");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
||||||
exit(EXIT_ARGS);
|
exit(EXIT_ARGS);
|
||||||
|
|||||||
@@ -581,6 +581,8 @@ preference to retaining points in sparse areas and dropping points in dense area
|
|||||||
\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.
|
\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
|
.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.
|
\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.
|
||||||
|
.IP \(bu 2
|
||||||
|
\fB\fC\-\-preserve\-point\-density\-threshold=\fR\fIlevel\fP: At the low zoom levels, do not reduce point density below the specified \fIlevel\fP, even if the specfied drop rate would normally call for it, so that low\-density areas of the map do not appear blank. The unit is the distance between preserved points, as a fraction of the size of a tile. Values of 32 or 64 are probably appropriate for typical marker sizes.
|
||||||
.RE
|
.RE
|
||||||
.SS Dropping a fraction of features to keep under tile size limits
|
.SS Dropping a fraction of features to keep under tile size limits
|
||||||
.RS
|
.RS
|
||||||
|
|||||||
+2591
File diff suppressed because it is too large
Load Diff
@@ -1200,6 +1200,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
read_file.close();
|
read_file.close();
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|||||||
@@ -1013,7 +1013,6 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
|
|||||||
|
|
||||||
std::vector<drawvec> simplified_arcs;
|
std::vector<drawvec> simplified_arcs;
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
for (auto ai = arcs.begin(); ai != arcs.end(); ++ai) {
|
for (auto ai = arcs.begin(); ai != arcs.end(); ++ai) {
|
||||||
if (simplified_arcs.size() < ai->second + 1) {
|
if (simplified_arcs.size() < ai->second + 1) {
|
||||||
simplified_arcs.resize(ai->second + 1);
|
simplified_arcs.resize(ai->second + 1);
|
||||||
@@ -1032,7 +1031,6 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
|
|||||||
} else {
|
} else {
|
||||||
simplified_arcs[ai->second] = dv;
|
simplified_arcs[ai->second] = dv;
|
||||||
}
|
}
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If necessary, merge some adjacent polygons into some other polygons
|
// If necessary, merge some adjacent polygons into some other polygons
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#ifndef VERSION_HPP
|
#ifndef VERSION_HPP
|
||||||
#define VERSION_HPP
|
#define VERSION_HPP
|
||||||
|
|
||||||
#define VERSION "v2.27.0"
|
#define VERSION "v2.28.0"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user