Merge pull request #180 from mapbox/coverage

Add a gamma-reduction test and base zoom/drop rate guessing tests
This commit is contained in:
Eric Fischer 2016-03-03 17:34:56 -08:00
commit b7f3fcfc7f
12 changed files with 112533 additions and 59 deletions

View File

@ -81,7 +81,7 @@ Options
* -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 at most 50,000 features in the densest tile.
You can also specify a marker-width with -Bg*width* to allow fewer features in the densest tile to
compensate for the larger marker.
compensate for the larger marker, or -Bf*number* to allow at most *number* 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)
@ -97,6 +97,8 @@ Options
* -r _rate_: Rate at which dots are dropped at zoom levels below basezoom (default 2.5).
If you use -rg, it will guess a drop rate that will keep at most 50,000 features in the densest tile.
You can also specify a marker-width with -rg*width* to allow fewer features in the densest tile to
compensate for the larger marker, or -rf*number* to allow at most *number* features in the densest tile.
* -g _gamma_: Rate at which especially dense dots are dropped (default 0, for no effect). A gamma of 2 reduces the number of dots less than a pixel apart to the square root of their original number.
### Doing more

View File

@ -1583,33 +1583,8 @@ int read_json(int argc, char **argv, char *fname, const char *layername, int max
tile[z].fullcount++;
// Keep in sync with write_tile()
if (gamma > 0) {
if (tile[z].gap > 0) {
if (map[i].index == tile[z].previndex) {
continue; // Exact duplicate: can't fulfil the gap requirement
}
if (exp(log((map[i].index - tile[z].previndex) / scale) * gamma) >= tile[z].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.
tile[z].gap = 0;
} else {
continue;
}
} else {
tile[z].gap = (map[i].index - tile[z].previndex) / scale;
if (tile[z].gap == 0) {
continue; // Exact duplicate: skip
} else if (tile[z].gap < 1) {
continue; // Narrow dot spacing: need to stretch out
} else {
tile[z].gap = 0; // Wider spacing than minimum: so pass through unchanged
}
}
tile[z].previndex = map[i].index;
if (manage_gap(map[i].index, &tile[z].previndex, scale, gamma, &tile[z].gap)) {
continue;
}
tile[z].count++;
@ -2105,12 +2080,15 @@ int main(int argc, char **argv) {
case 'B':
if (strcmp(optarg, "g") == 0) {
basezoom = -2;
basezoom_marker_width = 1;
} else if (optarg[0] == 'g') {
} else if (optarg[0] == 'g' || optarg[0] == 'f') {
basezoom = -2;
basezoom_marker_width = atof(optarg + 1);
if (basezoom_marker_width == 0) {
fprintf(stderr, "%s: Must specify marker width >0 with -Bg\n", argv[0]);
if (optarg[0] == 'g') {
basezoom_marker_width = atof(optarg + 1);
} else {
basezoom_marker_width = sqrt(50000 / atof(optarg + 1));
}
if (basezoom_marker_width == 0 || atof(optarg + 1) == 0) {
fprintf(stderr, "%s: Must specify value >0 with -B%c\n", argv[0], optarg[0]);
exit(EXIT_FAILURE);
}
} else {
@ -2154,6 +2132,17 @@ int main(int argc, char **argv) {
case 'r':
if (strcmp(optarg, "g") == 0) {
droprate = -2;
} else if (optarg[0] == 'g' || optarg[0] == 'f') {
droprate = -2;
if (optarg[0] == 'g') {
basezoom_marker_width = atof(optarg + 1);
} else {
basezoom_marker_width = sqrt(50000 / atof(optarg + 1));
}
if (basezoom_marker_width == 0 || atof(optarg + 1) == 0) {
fprintf(stderr, "%s: Must specify value >0 with -r%c\n", argv[0], optarg[0]);
exit(EXIT_FAILURE);
}
} else {
droprate = atof(optarg);
}

View File

@ -92,7 +92,7 @@ rather than a stream that can only be read sequentially.
\-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 at most 50,000 features in the densest tile.
You can also specify a marker\-width with \-Bg\fIwidth\fP to allow fewer features in the densest tile to
compensate for the larger marker.
compensate for the larger marker, or \-Bf\fInumber\fP to allow at most \fInumber\fP 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
@ -116,6 +116,8 @@ compensate for the larger marker.
.IP \(bu 2
\-r \fIrate\fP: Rate at which dots are dropped at zoom levels below basezoom (default 2.5).
If you use \-rg, it will guess a drop rate that will keep at most 50,000 features in the densest tile.
You can also specify a marker\-width with \-rg\fIwidth\fP to allow fewer features in the densest tile to
compensate for the larger marker, or \-rf\fInumber\fP to allow at most \fInumber\fP features in the densest tile.
.IP \(bu 2
\-g \fIgamma\fP: Rate at which especially dense dots are dropped (default 0, for no effect). A gamma of 2 reduces the number of dots less than a pixel apart to the square root of their original number.
.RE

4613
tests/muni/muni.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

60
tile.cc
View File

@ -563,6 +563,38 @@ void *partial_feature_worker(void *v) {
return NULL;
}
int manage_gap(unsigned long long index, unsigned long long *previndex, double scale, double gamma, double *gap) {
if (gamma > 0) {
if (*gap > 0) {
if (index == *previndex) {
return 1; // 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 {
return 1;
}
} else {
*gap = (index - *previndex) / scale;
if (*gap == 0) {
return 1; // Exact duplicate: skip
} else if (*gap < 1) {
return 1; // Narrow dot spacing: need to stretch out
} else {
*gap = 0; // Wider spacing than minimum: so pass through unchanged
}
}
*previndex = index;
}
return 0;
}
long long write_tile(char **geoms, char *metabase, char *stringpool, int z, unsigned tx, unsigned ty, int detail, int min_detail, int basezoom, struct pool **file_keys, char **layernames, sqlite3 *outdb, double droprate, int buffer, const char *fname, FILE **geomfile, int minzoom, int maxzoom, double todo, char *geomstart, volatile long long *along, double gamma, int nlayers, char *prevent, char *additional, int child_shards, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, volatile int *running) {
int line_detail;
double fraction = 1;
@ -767,32 +799,10 @@ long long write_tile(char **geoms, char *metabase, char *stringpool, int z, unsi
}
if (gamma > 0) {
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
}
unsigned long long index = index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2);
if (manage_gap(index, &previndex, scale, gamma, &gap)) {
continue;
}
previndex = index;
}
}

2
tile.h
View File

@ -29,6 +29,8 @@ long long write_tile(char **geom, char *metabase, char *stringpool, unsigned *fi
int traverse_zooms(int *geomfd, off_t *geom_size, char *metabase, char *stringpool, struct pool **file_keys, unsigned *midx, unsigned *midy, char **layernames, int maxzoom, int minzoom, int basezoom, sqlite3 *outdb, double droprate, int buffer, const char *fname, const char *tmpdir, double gamma, int nlayers, char *prevent, char *additional, int full_detail, int low_detail, int min_detail, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y);
int manage_gap(unsigned long long index, unsigned long long *previndex, double scale, double gamma, double *gap);
extern unsigned initial_x, initial_y;
extern int geometry_scale;
extern int quiet;