diff --git a/README.md b/README.md index 894696b..ca2c8d1 100644 --- a/README.md +++ b/README.md @@ -527,6 +527,7 @@ the same layer, enclose them in an `all` expression so they will all be evaluate * `-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. * `--clip-bounding-box=`*minlon*`,`*minlat*`,`*maxlon*`,`*maxlat*: Clip all features to the specified bounding box. + * `--split-complex-polygons=`*limit*`: Subdivide polygons with more than *limit* vertices into multiple features. ### Setting or disabling tile size limits diff --git a/geometry.cpp b/geometry.cpp index 24aeb7e..a632725 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -975,16 +975,16 @@ drawvec fix_polygon(drawvec &geom) { return out; } -std::vector chop_polygon(std::vector &geoms) { +std::vector chop_polygon(std::vector &geoms, size_t n) { while (1) { bool again = false; std::vector out; for (size_t i = 0; i < geoms.size(); i++) { - if (geoms[i].size() > 700) { + if (geoms[i].size() > n) { static bool warned = false; if (!warned) { - fprintf(stderr, "Warning: splitting up polygon with more than 700 sides\n"); + fprintf(stderr, "Warning: splitting up polygon with more than %zu sides\n", n); warned = true; } diff --git a/geometry.hpp b/geometry.hpp index 79b8f47..14e1c79 100644 --- a/geometry.hpp +++ b/geometry.hpp @@ -71,7 +71,7 @@ int quick_check(long long *bbox, int z, long long buffer); drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds, double simplification, size_t retain, drawvec const &shared_nodes); drawvec reorder_lines(drawvec &geom); drawvec fix_polygon(drawvec &geom); -std::vector chop_polygon(std::vector &geoms); +std::vector chop_polygon(std::vector &geoms, size_t n); void check_polygon(drawvec &geom); double get_area(drawvec &geom, size_t i, size_t j); double get_mp_area(drawvec &geom); diff --git a/main.cpp b/main.cpp index ae41d82..4cc6c23 100644 --- a/main.cpp +++ b/main.cpp @@ -77,6 +77,7 @@ size_t max_tile_features = 200000; int cluster_distance = 0; long justx = -1, justy = -1; std::string attribute_for_id = ""; +size_t polygon_split = 0; int prevent[256]; int additional[256]; @@ -2596,6 +2597,7 @@ int main(int argc, char **argv) { {"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}, {"clip-bounding-box", required_argument, 0, '~'}, + {"split-complex-polygons", required_argument, 0, '~'}, {"Filtering tile contents", 0, 0, 0}, {"prefilter", required_argument, 0, 'C'}, @@ -2695,6 +2697,8 @@ int main(int argc, char **argv) { fprintf(stderr, "%s: Can't parse bounding box --%s=%s\n", argv[0], opt, optarg); exit(EXIT_FAILURE); } + } else if (strcmp(opt, "split-complex-polygons") == 0) { + polygon_split = atoi(optarg); } else if (strcmp(opt, "use-attribute-for-id") == 0) { attribute_for_id = optarg; } else { diff --git a/main.hpp b/main.hpp index 8d89ab6..9992cd4 100644 --- a/main.hpp +++ b/main.hpp @@ -48,6 +48,7 @@ extern size_t max_tile_size; extern size_t max_tile_features; extern int cluster_distance; extern std::string attribute_for_id; +extern size_t polygon_split; int mkstemp_cloexec(char *name); FILE *fopen_oflag(const char *name, const char *mode, int oflag); diff --git a/tile.cpp b/tile.cpp index cf41982..c9a521b 100644 --- a/tile.cpp +++ b/tile.cpp @@ -499,6 +499,10 @@ void *partial_feature_worker(void *v) { std::vector geoms; geoms.push_back(geom); + if (t == VT_POLYGON && polygon_split > 0) { + geoms = chop_polygon(geoms, polygon_split); + } + if (t == VT_POLYGON) { // Scaling may have made the polygon degenerate. // Give Clipper a chance to try to fix it.