mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 16:35:40 +02:00
* docs: correct README statements that don't match the code
Cross-checked README.md against the option tables in main.cpp,
tile-join.cpp, decode.cpp, jsontool.cpp and overzoom.cpp, plus
options.hpp for the -pX/-aX letter assignments.
Incorrect:
* -aD and -aS were swapped. options.hpp assigns 'D' to
A_COALESCE_FRACTION_AS_NEEDED and 'S' to
A_COALESCE_DENSEST_AS_NEEDED, the opposite of what was documented.
* --limit-base-zoom-to-maximum-zoom was given as -Pb. It is a
prevent flag (P_BASEZOOM_ABOVE_MAXZOOM = 'b'), so it is -pb; -P
is --read-parallel and takes no letters.
* --retain-points-multiplier referred to --tile-size-limit, which
is not an option. The limit it extends is --maximum-tile-bytes.
* The dot-dropping description said tippecanoe "drops 1/2.5 of the
dots for each zoom level above the point base zoom". It keeps
1/2.5 of them, at zooms below the base zoom (prep_drop_states
sets interval only where i < basezoom).
* The default tileset name was given as "file.json". make_metadata
sets both name and description from the output file or directory
name.
* tile-join -r/--read-from was described as a "list of input
mbtiles"; it names a file to read that list from, one per line.
* tippecanoe-decode's -I and -F were given as --integer and
--fraction. Those work only as getopt abbreviations; the real
names are --integer-coordinates and --fractional-coordinates.
* Development notes said C++11 and suggested g++-5. The Makefile
builds with -std=c++17.
* Malformed references: "-quiet" and "no-simplification-of-shared-nodes".
Undocumented options now covered:
* tippecanoe: -aa/--keep-point-cluster-position,
--preserve-multiplier-density-threshold, -H/--help, the count
operation for --accumulate-attribute, and the
point_count_abbreviated cluster attribute.
* tile-join: -O as the short form of --overzoom, -q/--quiet,
--exclude-all-tile-attributes, --exclude-all-tile-geometries.
* tippecanoe-decode: -y/--include, -x/--exclude-metadata-row.
* tippecanoe-overzoom: -x/--exclude, --exclude-prefix, -J,
-S/--line-simplification, --tiny-polygon-size,
--deduplicate-by-id, --no-tile-compression, -t/--source-tile,
-o/--output, and the long names for -b, -d, -y, -j, -m and -E.
Also noted that CSV latitude/longitude columns are matched
case-insensitively as substrings, added file.csv to the usage
synopsis, and explained the -a/-p letter-bundle syntax that the
short forms throughout the document rely on.
Every newly documented flag was run against a built binary. The
man page is regenerated from README.md per the Makefile rule; that
also picks up the All Streets link fix from #400, which had not
been regenerated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MvSCpD1yQZhRT5iMU9yufQ
* Hide --unidecode-data from the generated usage messages
The option has done nothing since 533e000 removed the only caller of
unidecode_smash(), so listing it advertises behavior the tools don't
have. Move it after the empty-name entry that ends the usage listing,
the same place --no-polygon-splitting and the debug options sit, so it
is still accepted but no longer offered.
This is the situation #409 already fixed for tile-join's
--use-attribute-for-id, but it applies to all three tools that take
--unidecode-data, not just tile-join: main.cpp listed it under
"Filtering features by attributes" and overzoom.cpp under "Modifying
feature attributes", both ahead of the terminator.
tile-join's "Modifying feature attributes" heading covered only this
option, so it goes too rather than being left empty. overzoom.cpp had
no hidden group at all, so one is added. In main.cpp and overzoom.cpp
the heading keeps its other options and stays.
strip_usage_headings() copies every entry with a non-zero val, so the
moved option still reaches getopt_long(); confirmed by running each
tool with --unidecode-data and checking it is absent from --help.
make test passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MvSCpD1yQZhRT5iMU9yufQ
---------
Co-authored-by: Claude <noreply@anthropic.com>
306 lines
6.8 KiB
C++
306 lines
6.8 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <string>
|
|
#include <set>
|
|
#include "errors.hpp"
|
|
#include "mvt.hpp"
|
|
#include "geometry.hpp"
|
|
#include "evaluator.hpp"
|
|
#include "attribute.hpp"
|
|
#include "text.hpp"
|
|
#include "read_json.hpp"
|
|
#include "projection.hpp"
|
|
#include "usage.hpp"
|
|
|
|
extern char *optarg;
|
|
extern int optind;
|
|
|
|
int detail = 12; // tippecanoe-style: mvt extent == 1 << detail
|
|
int buffer = 5; // tippecanoe-style: mvt buffer == extent * buffer / 256;
|
|
bool demultiply = false;
|
|
bool do_compress = true;
|
|
bool deduplicate_by_id = false;
|
|
|
|
std::string filter;
|
|
bool preserve_input_order = false;
|
|
std::unordered_map<std::string, attribute_op> attribute_accum;
|
|
std::vector<std::string> unidecode_data;
|
|
|
|
std::set<std::string> keep;
|
|
std::set<std::string> exclude;
|
|
std::vector<std::string> exclude_prefix;
|
|
|
|
static const struct option long_options[] = {
|
|
{"Output tile", 0, 0, 0},
|
|
{"output", required_argument, 0, 'o'},
|
|
{"source-tile", required_argument, 0, 't'},
|
|
{"no-tile-compression", no_argument, 0, 'd' & 0x1F},
|
|
|
|
{"Tile resolution", 0, 0, 0},
|
|
{"full-detail", required_argument, 0, 'd'},
|
|
{"buffer", required_argument, 0, 'b'},
|
|
|
|
{"Filtering feature attributes", 0, 0, 0},
|
|
{"include", required_argument, 0, 'y'},
|
|
{"exclude", required_argument, 0, 'x'},
|
|
{"exclude-prefix", required_argument, 0, 'x' & 0x1F},
|
|
|
|
{"Modifying feature attributes", 0, 0, 0},
|
|
{"accumulate-attribute", required_argument, 0, 'E'},
|
|
|
|
{"Filtering features", 0, 0, 0},
|
|
{"feature-filter", required_argument, 0, 'j'},
|
|
{"feature-filter-file", required_argument, 0, 'J'},
|
|
{"filter-points-multiplier", no_argument, 0, 'm'},
|
|
{"deduplicate-by-id", no_argument, 0, 'i' & 0x1F},
|
|
|
|
{"Line and polygon simplification", 0, 0, 0},
|
|
{"line-simplification", required_argument, 0, 'S'},
|
|
{"tiny-polygon-size", required_argument, 0, 's' & 0x1F},
|
|
|
|
{"Reordering features within the tile", 0, 0, 0},
|
|
{"preserve-input-order", no_argument, 0, 'o' & 0x1F},
|
|
|
|
{"", 0, 0, 0},
|
|
{"unidecode-data", required_argument, 0, 'u' & 0x1F},
|
|
|
|
{0, 0, 0, 0},
|
|
};
|
|
|
|
// the options above, with the usage message headings removed
|
|
static struct option real_long_options[sizeof(long_options) / sizeof(long_options[0])];
|
|
|
|
void usage(char **argv) {
|
|
static const char *const forms[] = {
|
|
"[options] tile.pbf.gz oz/ox/oy nz/nx/ny",
|
|
"[options] --source-tile=nz/nx/ny tile.pbf.gz oz/ox/oy ...",
|
|
NULL,
|
|
};
|
|
static const struct usage_required_option required[] = {
|
|
{"output", "newtile.pbf.gz", 0},
|
|
{NULL, NULL, 0},
|
|
};
|
|
|
|
print_usage(stderr, argv[0], forms, long_options, required);
|
|
fprintf(stderr, "\nThe tile nz/nx/ny is created from the tile or tiles oz/ox/oy that contain it.\n");
|
|
fprintf(stderr, "In the second form, each source tile is named by a file name and a z/x/y pair.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
std::string read_json_file(const char *fname) {
|
|
std::string out;
|
|
|
|
FILE *f = fopen(fname, "r");
|
|
if (f == NULL) {
|
|
perror(optarg);
|
|
exit(EXIT_OPEN);
|
|
}
|
|
|
|
char buf[2000];
|
|
size_t nread;
|
|
while ((nread = fread(buf, sizeof(char), 2000, f)) != 0) {
|
|
out += std::string(buf, nread);
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return out;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int i;
|
|
const char *outtile = NULL;
|
|
const char *outfile = NULL;
|
|
double simplification = 0;
|
|
double tiny_polygon_size = 0;
|
|
|
|
std::vector<input_tile> sources;
|
|
|
|
strip_usage_headings(long_options, real_long_options);
|
|
std::string getopt_str = getopt_string(real_long_options);
|
|
|
|
int option_index = 0;
|
|
while ((i = getopt_long(argc, argv, getopt_str.c_str(), real_long_options, &option_index)) != -1) {
|
|
switch (i) {
|
|
case 'y':
|
|
keep.insert(optarg);
|
|
break;
|
|
|
|
case 'x':
|
|
exclude.insert(optarg);
|
|
break;
|
|
|
|
case 'x' & 0x1F:
|
|
exclude_prefix.push_back(optarg);
|
|
break;
|
|
|
|
case 'o':
|
|
outfile = optarg;
|
|
break;
|
|
|
|
case 'd':
|
|
detail = atoi(optarg);
|
|
break;
|
|
|
|
case 'b':
|
|
buffer = atoi(optarg);
|
|
break;
|
|
|
|
case 'm':
|
|
demultiply = true;
|
|
break;
|
|
|
|
case 'j':
|
|
filter = optarg;
|
|
break;
|
|
|
|
case 'J':
|
|
filter = read_json_file(optarg);
|
|
break;
|
|
|
|
case 'o' & 0x1F:
|
|
preserve_input_order = true;
|
|
break;
|
|
|
|
case 'E':
|
|
set_attribute_accum(attribute_accum, optarg, argv);
|
|
break;
|
|
|
|
case 'u' & 0x1F:
|
|
unidecode_data = read_unidecode(optarg);
|
|
break;
|
|
|
|
case 't':
|
|
outtile = optarg;
|
|
break;
|
|
|
|
case 's' & 0x1F:
|
|
tiny_polygon_size = atof(optarg);
|
|
break;
|
|
|
|
case 'S':
|
|
simplification = atof(optarg);
|
|
break;
|
|
|
|
case 'd' & 0x1F:
|
|
do_compress = false;
|
|
break;
|
|
|
|
case 'i' & 0x1F: {
|
|
deduplicate_by_id = true;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
fprintf(stderr, "Unrecognized flag -%c\n", i);
|
|
usage(argv);
|
|
}
|
|
}
|
|
|
|
std::vector<input_tile> its;
|
|
int nz, nx, ny;
|
|
|
|
if (outfile == NULL) {
|
|
fprintf(stderr, "%s: must specify -o newtile.pbf.gz\n", argv[0]);
|
|
usage(argv);
|
|
}
|
|
|
|
if (outtile == NULL) { // single input
|
|
if (argc - optind != 3) {
|
|
fprintf(stderr, "Wrong number of arguments\n");
|
|
usage(argv);
|
|
}
|
|
|
|
const char *infile = argv[optind + 0];
|
|
|
|
int oz, ox, oy;
|
|
if (sscanf(argv[optind + 1], "%d/%d/%d", &oz, &ox, &oy) != 3) {
|
|
fprintf(stderr, "%s: not in z/x/y form\n", argv[optind + 1]);
|
|
usage(argv);
|
|
}
|
|
|
|
if (sscanf(argv[optind + 2], "%d/%d/%d", &nz, &nx, &ny) != 3) {
|
|
fprintf(stderr, "%s: not in z/x/y form\n", argv[optind + 2]);
|
|
usage(argv);
|
|
}
|
|
|
|
input_tile s;
|
|
s.tile = infile;
|
|
s.z = oz;
|
|
s.x = ox;
|
|
s.y = oy;
|
|
|
|
sources.push_back(s);
|
|
} else { // multiple inputs
|
|
if ((argc - optind) % 2 != 0) {
|
|
fprintf(stderr, "Unpaired arguments\n");
|
|
usage(argv);
|
|
}
|
|
|
|
if (sscanf(outtile, "%d/%d/%d", &nz, &nx, &ny) != 3) {
|
|
fprintf(stderr, "%s: not in z/x/y form\n", outtile);
|
|
usage(argv);
|
|
}
|
|
|
|
for (i = optind; i + 1 < argc; i += 2) {
|
|
int oz, ox, oy;
|
|
if (sscanf(argv[i + 1], "%d/%d/%d", &oz, &ox, &oy) != 3) {
|
|
fprintf(stderr, "%s: not in z/x/y form\n", argv[i + 1]);
|
|
usage(argv);
|
|
}
|
|
|
|
input_tile s;
|
|
s.tile = argv[i];
|
|
s.z = oz;
|
|
s.x = ox;
|
|
s.y = oy;
|
|
|
|
sources.push_back(s);
|
|
}
|
|
}
|
|
|
|
std::string out;
|
|
|
|
{
|
|
json_object *json_filter = NULL;
|
|
if (filter.size() > 0) {
|
|
json_filter = parse_filter(filter.c_str());
|
|
}
|
|
|
|
for (auto const &s : sources) {
|
|
std::string tile;
|
|
char buf[1000];
|
|
int len;
|
|
|
|
FILE *f = fopen(s.tile.c_str(), "rb");
|
|
if (f == NULL) {
|
|
perror(s.tile.c_str());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while ((len = fread(buf, sizeof(char), 1000, f)) > 0) {
|
|
tile.append(std::string(buf, len));
|
|
}
|
|
fclose(f);
|
|
|
|
input_tile t = s;
|
|
t.tile = std::move(tile);
|
|
its.push_back(std::move(t));
|
|
}
|
|
|
|
out = overzoom(its, nz, nx, ny, detail, buffer, keep, exclude, exclude_prefix, do_compress, NULL, demultiply, json_filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, std::vector<mvt_layer>(), "", "", SIZE_MAX, std::vector<clipbbox>(), deduplicate_by_id);
|
|
}
|
|
|
|
FILE *f = fopen(outfile, "wb");
|
|
if (f == NULL) {
|
|
perror(outfile);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fwrite(out.c_str(), sizeof(char), out.size(), f);
|
|
fclose(f);
|
|
|
|
return 0;
|
|
}
|