mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 16:35:40 +02:00
Add --reject-null-geometry and more GeoJSON geometry validation
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
# 2.38.0
|
||||
|
||||
* Add --reject-null-geometry and more checking of GeoJSON polygon and linestring validity
|
||||
|
||||
# 2.37.0
|
||||
|
||||
* Speed up tile-join overzooming and make it use less memory, by not including empty child tiles in the enumeration
|
||||
|
||||
@@ -533,6 +533,7 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
|
||||
* `-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.
|
||||
* `-aP` or `--convert-polygons-to-label-points`: Replace polygon geometries with a label point or points for the polygon in each tile it intersects.
|
||||
* `--reject-null-geometry`: Exit with an error when a feature has a `null` geometry instead of just giving a warning.
|
||||
|
||||
### Setting or disabling tile size limits
|
||||
|
||||
|
||||
@@ -19,5 +19,6 @@
|
||||
#define EXIT_UNLINK 118
|
||||
#define EXIT_UTF8 119
|
||||
#define EXIT_WRITE 120
|
||||
#define EXIT_INCORRECT_GEOMETRY 121
|
||||
|
||||
// avoid 124, 125, 126, 127, 137, which are used by GNU timeout
|
||||
|
||||
@@ -49,6 +49,10 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
|
||||
fprintf(stderr, "%s:%d: null geometry (additional not reported): ", sst->fname, sst->line);
|
||||
json_context(feature);
|
||||
warned = 1;
|
||||
|
||||
if (additional[A_REJECT_NULL_GEOMETRY]) {
|
||||
exit(EXIT_INCORRECT_GEOMETRY);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -3214,6 +3214,7 @@ int main(int argc, char **argv) {
|
||||
{"reverse-source-polygon-winding", no_argument, &prevent[P_REVERSE_SOURCE_POLYGON_WINDING], 1},
|
||||
{"clip-bounding-box", required_argument, 0, '~'},
|
||||
{"convert-polygons-to-label-points", no_argument, &additional[A_GENERATE_POLYGON_LABEL_POINTS], 1},
|
||||
{"reject-null-geometry", no_argument, &additional[A_REJECT_NULL_GEOMETRY], 1},
|
||||
|
||||
{"Filtering tile contents", 0, 0, 0},
|
||||
{"prefilter", required_argument, 0, 'C'},
|
||||
|
||||
@@ -695,6 +695,8 @@ the line or polygon within one tile unit of its proper location. You can probabl
|
||||
\fB\fC\-\-clip\-bounding\-box=\fR\fIminlon\fP\fB\fC,\fR\fIminlat\fP\fB\fC,\fR\fImaxlon\fP\fB\fC,\fR\fImaxlat\fP: Clip all features to the specified bounding box.
|
||||
.IP \(bu 2
|
||||
\fB\fC\-aP\fR or \fB\fC\-\-convert\-polygons\-to\-label\-points\fR: Replace polygon geometries with a label point or points for the polygon in each tile it intersects.
|
||||
.IP \(bu 2
|
||||
\fB\fC\-\-reject\-null\-geometry\fR: Exit with an error when a feature has a \fB\fCnull\fR geometry instead of just giving a warning.
|
||||
.RE
|
||||
.SS Setting or disabling tile size limits
|
||||
.RS
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define A_HILBERT ((int) 'h')
|
||||
#define A_VISVALINGAM ((int) 'v')
|
||||
#define A_GENERATE_POLYGON_LABEL_POINTS ((int) 'P')
|
||||
#define A_REJECT_NULL_GEOMETRY ((int) '0')
|
||||
|
||||
#define P_SIMPLIFY ((int) 's')
|
||||
#define P_SIMPLIFY_LOW ((int) 'S')
|
||||
|
||||
@@ -103,6 +103,14 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna
|
||||
}
|
||||
|
||||
if (t == GEOM_POLYGON) {
|
||||
if (out.size() < 3) {
|
||||
fprintf(stderr, "%s:%d: polygon must contain at least three points: ", fname, line);
|
||||
json_context(j);
|
||||
fprintf(stderr, "%s:%d: polygon must contain at least three points: ", fname, line);
|
||||
json_context(feature);
|
||||
exit(EXIT_INCORRECT_GEOMETRY);
|
||||
}
|
||||
|
||||
// Note that this is not using the correct meaning of closepath.
|
||||
//
|
||||
// We are using it here to close an entire Polygon, to distinguish
|
||||
@@ -114,6 +122,16 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna
|
||||
|
||||
out.push_back(draw(VT_CLOSEPATH, 0, 0));
|
||||
}
|
||||
|
||||
if (t == GEOM_LINESTRING) {
|
||||
if (out.size() < 2) {
|
||||
fprintf(stderr, "%s:%d: linestring must contain at least two points: ", fname, line);
|
||||
json_context(j);
|
||||
fprintf(stderr, "%s:%d: linestring must contain at least two points: ", fname, line);
|
||||
json_context(feature);
|
||||
exit(EXIT_INCORRECT_GEOMETRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stringify_value(json_object *value, int &type, std::string &stringified, const char *reading, int line, json_object *feature) {
|
||||
|
||||
@@ -1609,6 +1609,34 @@ serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos
|
||||
}
|
||||
}
|
||||
|
||||
bool legit_geometry(int t, const drawvec &g) {
|
||||
bool legit = false;
|
||||
|
||||
for (size_t i = 0; i < g.size(); i++) {
|
||||
if (g[i].op == VT_MOVETO) {
|
||||
size_t j;
|
||||
|
||||
for (j = i + 1; j < g.size(); j++) {
|
||||
if (g[j].op != VT_LINETO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (t == VT_LINE && j < i + 2) {
|
||||
return false;
|
||||
}
|
||||
if (t == VT_POLYGON && j < i + 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
legit = true; // must contain at least one ring
|
||||
i = j - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return legit;
|
||||
}
|
||||
|
||||
struct run_prefilter_args {
|
||||
decompressor *geoms = NULL;
|
||||
std::atomic<long long> *geompos_in = NULL;
|
||||
@@ -1657,6 +1685,11 @@ void *run_prefilter(void *v) {
|
||||
tmp_layer.extent = 1LL << 32;
|
||||
tmp_layer.name = (*(rpa->layer_unmaps))[sf.segment][sf.layer];
|
||||
|
||||
// make sure the geometry is actually legal geojson
|
||||
if (!legit_geometry(sf.t, sf.geometry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sf.t == VT_POLYGON) {
|
||||
sf.geometry = close_poly(sf.geometry);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#ifndef VERSION_HPP
|
||||
#define VERSION_HPP
|
||||
|
||||
#define VERSION "v2.37.0"
|
||||
#define VERSION "v2.38.0"
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user