From 9eb3a7f7ecfa84852d70a98dbd4070f1bcc502b8 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 5 May 2017 10:56:50 -0700 Subject: [PATCH] Enforce polygon winding and closure rules in tippecanoe-decode --- CHANGELOG.md | 4 ++++ README.md | 1 + decode.cpp | 23 ++++++++++++++++++++++- man/tippecanoe.1 | 2 ++ version.hpp | 2 +- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67ef478..00cf0ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.17.7 + +* Enforce polygon winding and closure rules in tippecanoe-decode + ## 1.17.6 * Add tile-join options to set name, attribution, description diff --git a/README.md b/README.md index c536122..0d5745e 100644 --- a/README.md +++ b/README.md @@ -482,3 +482,4 @@ resolutions. * `-z` _maxzoom_: Specify the highest zoom level to decode from the tileset * `-Z` _minzoom_: Specify the lowest zoom level to decode from the tileset * `-l` _layer_: Decode only layers with the specified names. (Multiple `-l` options can be specified.) + * `-f`: Decode tiles even if polygon ring order or closure problems are detected diff --git a/decode.cpp b/decode.cpp index cc84daf..c55288e 100644 --- a/decode.cpp +++ b/decode.cpp @@ -19,6 +19,7 @@ int minzoom = 0; int maxzoom = 32; +bool force = false; void printq(const char *s) { putchar('"'); @@ -261,6 +262,15 @@ void handle(std::string message, int z, unsigned x, unsigned y, int describe, st rings[n].push_back(ops[i]); } } + + if (i >= ops.size() || ops[i + 1].op == VT_MOVETO) { + if (ops[i].op != VT_CLOSEPATH) { + fprintf(stderr, "Ring does not end with closepath (ends with %d)\n", ops[i].op); + if (!force) { + exit(EXIT_FAILURE); + } + } + } } int outer = 0; @@ -290,6 +300,13 @@ void handle(std::string message, int z, unsigned x, unsigned y, int describe, st int state = 0; for (size_t i = 0; i < rings.size(); i++) { + if (i == 0 && areas[i] < 0) { + fprintf(stderr, "Polygon begins with an inner ring\n"); + if (!force) { + exit(EXIT_FAILURE); + } + } + if (areas[i] >= 0) { if (state != 0) { // new multipolygon @@ -489,7 +506,7 @@ int main(int argc, char **argv) { int i; std::set to_decode; - while ((i = getopt(argc, argv, "t:Z:z:l:")) != -1) { + while ((i = getopt(argc, argv, "t:Z:z:l:f")) != -1) { switch (i) { case 't': set_projection_or_exit(optarg); @@ -507,6 +524,10 @@ int main(int argc, char **argv) { to_decode.insert(optarg); break; + case 'f': + force = true; + break; + default: usage(argv); } diff --git a/man/tippecanoe.1 b/man/tippecanoe.1 index 010a659..167a114 100644 --- a/man/tippecanoe.1 +++ b/man/tippecanoe.1 @@ -568,4 +568,6 @@ resolutions. \fB\fC\-Z\fR \fIminzoom\fP: Specify the lowest zoom level to decode from the tileset .IP \(bu 2 \fB\fC\-l\fR \fIlayer\fP: Decode only layers with the specified names. (Multiple \fB\fC\-l\fR options can be specified.) +.IP \(bu 2 +\fB\fC\-f\fR: Decode tiles even if polygon ring order or closure problems are detected .RE diff --git a/version.hpp b/version.hpp index 22946d4..c70088e 100644 --- a/version.hpp +++ b/version.hpp @@ -1 +1 @@ -#define VERSION "tippecanoe v1.17.6\n" +#define VERSION "tippecanoe v1.17.7\n"