diff --git a/CHANGELOG.md b/CHANGELOG.md index f5fcfa8..e70f954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.29.1 + +* Add --use-source-polygon-winding and --reverse-source-polygon-winding + ## 1.29.0 * Add the option to specify layer file, name, and description as JSON diff --git a/README.md b/README.md index b05fb66..d7a68c0 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,8 @@ Example: to retain only major TIGER roads at low zoom levels: ### Trying to correct bad source geometry * `-aw` or `--detect-longitude-wraparound`: Detect when adjacent points within a feature jump to the other side of the world, and try to fix the geometry. + * `-pw` or `--use-source-polygon-winding`: Instead of respecting GeoJSON polygon ring order, use the original polygon winding in the source data to distinguish inner (clockwise) and outer (counterclockwise) polygon rings. + * `-pW` or `--reverse-source-polygon-winding`: Instead of respecting GeoJSON polygon ring order, use the opposite of the original polygon winding in the source data to distinguish inner (counterclockwise) and outer (clockwise) polygon rings. ### Setting or disabling tile size limits diff --git a/geometry.cpp b/geometry.cpp index 980c061..6f69abe 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -19,6 +19,7 @@ #include "projection.hpp" #include "serial.hpp" #include "main.hpp" +#include "options.hpp" static int pnpoly(drawvec &vert, size_t start, size_t nvert, long long testx, long long testy); static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax); @@ -912,8 +913,21 @@ drawvec fix_polygon(drawvec &geom) { // Reverse ring if winding order doesn't match // inner/outer expectation - double area = get_area(ring, 0, ring.size()); - if ((area > 0) != outer) { + bool reverse_ring = false; + if (prevent[P_USE_SOURCE_POLYGON_WINDING]) { + // GeoJSON winding is reversed from vector winding + reverse_ring = true; + } else if (prevent[P_REVERSE_SOURCE_POLYGON_WINDING]) { + // GeoJSON winding is reversed from vector winding + reverse_ring = false; + } else { + double area = get_area(ring, 0, ring.size()); + if ((area > 0) != outer) { + reverse_ring = true; + } + } + + if (reverse_ring) { drawvec tmp; for (int a = ring.size() - 1; a >= 0; a--) { tmp.push_back(ring[a]); diff --git a/main.cpp b/main.cpp index 011cf18..1dbe289 100644 --- a/main.cpp +++ b/main.cpp @@ -2552,6 +2552,8 @@ int main(int argc, char **argv) { {"Trying to correct bad source geometry", 0, 0, 0}, {"detect-longitude-wraparound", no_argument, &additional[A_DETECT_WRAPAROUND], 1}, + {"use-source-polygon-winding", no_argument, &prevent[P_USE_SOURCE_POLYGON_WINDING], 1}, + {"reverse-source-polygon-winding", no_argument, &prevent[P_REVERSE_SOURCE_POLYGON_WINDING], 1}, {"Filtering tile contents", 0, 0, 0}, {"prefilter", required_argument, 0, 'C'}, diff --git a/man/tippecanoe.1 b/man/tippecanoe.1 index 1674791..a2d7a09 100644 --- a/man/tippecanoe.1 +++ b/man/tippecanoe.1 @@ -361,6 +361,10 @@ the line or polygon within one tile unit of its proper location. You can probabl .RS .IP \(bu 2 \fB\fC\-aw\fR or \fB\fC\-\-detect\-longitude\-wraparound\fR: Detect when adjacent points within a feature jump to the other side of the world, and try to fix the geometry. +.IP \(bu 2 +\fB\fC\-pw\fR or \fB\fC\-\-use\-source\-polygon\-winding\fR: Instead of respecting GeoJSON polygon ring order, use the original polygon winding in the source data to distinguish inner (clockwise) and outer (counterclockwise) polygon rings. +.IP \(bu 2 +\fB\fC\-pW\fR or \fB\fC\-\-reverse\-source\-polygon\-winding\fR: Instead of respecting GeoJSON polygon ring order, use the opposite of the original polygon winding in the source data to distinguish inner (counterclockwise) and outer (clockwise) polygon rings. .RE .SS Setting or disabling tile size limits .RS diff --git a/options.hpp b/options.hpp index e97dd72..0b113f6 100644 --- a/options.hpp +++ b/options.hpp @@ -35,6 +35,8 @@ #define P_TINY_POLYGON_REDUCTION ((int) 't') #define P_TILE_COMPRESSION ((int) 'C') #define P_TILE_STATS ((int) 'g') +#define P_USE_SOURCE_POLYGON_WINDING ((int) 'w') +#define P_REVERSE_SOURCE_POLYGON_WINDING ((int) 'W') extern int prevent[256]; extern int additional[256]; diff --git a/tests/polygon-winding/in.json b/tests/polygon-winding/in.json new file mode 100644 index 0000000..c736d69 --- /dev/null +++ b/tests/polygon-winding/in.json @@ -0,0 +1,19 @@ + { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ], + [ + [100.8, 0.8], + [100.8, 0.2], + [100.2, 0.2], + [100.2, 0.8], + [100.8, 0.8] + ] + ] + } diff --git a/tests/polygon-winding/out/-z0.json b/tests/polygon-winding/out/-z0.json new file mode 100644 index 0000000..c46816a --- /dev/null +++ b/tests/polygon-winding/out/-z0.json @@ -0,0 +1,18 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "100.000000,0.000000,101.000000,1.000000", +"center": "100.000000,0.000000,0", +"description": "tests/polygon-winding/out/-z0.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/polygon-winding/out/-z0.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 100.986328, 1.054628 ], [ 100.986328, 0.000000 ], [ 99.931641, 0.000000 ], [ 99.931641, 1.054628 ], [ 100.986328, 1.054628 ] ], [ [ 100.195312, 0.263671 ], [ 100.722656, 0.263671 ], [ 100.722656, 0.878872 ], [ 100.195312, 0.878872 ], [ 100.195312, 0.263671 ] ] ] } } +] } +] } +] } diff --git a/tests/polygon-winding/out/-z0_--reverse-source-polygon-winding.json b/tests/polygon-winding/out/-z0_--reverse-source-polygon-winding.json new file mode 100644 index 0000000..6e638f1 --- /dev/null +++ b/tests/polygon-winding/out/-z0_--reverse-source-polygon-winding.json @@ -0,0 +1,18 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "100.000000,0.000000,101.000000,1.000000", +"center": "100.000000,0.000000,0", +"description": "tests/polygon-winding/out/-z0_--reverse-source-polygon-winding.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/polygon-winding/out/-z0_--reverse-source-polygon-winding.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 100.722656, 0.878872 ], [ 100.722656, 0.263671 ], [ 100.195312, 0.263671 ], [ 100.195312, 0.878872 ], [ 100.722656, 0.878872 ] ] ] } } +] } +] } +] } diff --git a/tests/polygon-winding/out/-z0_--use-source-polygon-winding.json b/tests/polygon-winding/out/-z0_--use-source-polygon-winding.json new file mode 100644 index 0000000..bb6d8cb --- /dev/null +++ b/tests/polygon-winding/out/-z0_--use-source-polygon-winding.json @@ -0,0 +1,18 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "100.000000,0.000000,101.000000,1.000000", +"center": "100.000000,0.000000,0", +"description": "tests/polygon-winding/out/-z0_--use-source-polygon-winding.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/polygon-winding/out/-z0_--use-source-polygon-winding.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 100.986328, 1.054628 ], [ 100.986328, 0.000000 ], [ 99.931641, 0.000000 ], [ 99.931641, 1.054628 ], [ 100.986328, 1.054628 ] ], [ [ 100.195312, 0.263671 ], [ 100.722656, 0.263671 ], [ 100.722656, 0.878872 ], [ 100.195312, 0.878872 ], [ 100.195312, 0.263671 ] ] ] } } +] } +] } +] } diff --git a/version.hpp b/version.hpp index 83d12f6..a3433c9 100644 --- a/version.hpp +++ b/version.hpp @@ -1,6 +1,6 @@ #ifndef VERSION_HPP #define VERSION_HPP -#define VERSION "tippecanoe v1.29.0\n" +#define VERSION "tippecanoe v1.29.1\n" #endif