mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-03-23 20:35:16 +00:00
Factor out clipping to tile boundaries; test random attributes & layers
This commit is contained in:
parent
daf1941ba9
commit
5194a39c16
13
Makefile
13
Makefile
@ -87,16 +87,17 @@ test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) parallel-test pb
|
||||
|
||||
parallel-test:
|
||||
mkdir -p tests/parallel
|
||||
perl -e 'for ($$i = 0; $$i < 20; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; print "{ \"type\": \"Feature\", \"properties\": { \"yes\": \"no\", \"who\": 1 }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in1.json
|
||||
perl -e 'for ($$i = 0; $$i < 20; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; $$k = rand(1); $$v = rand(1); print "{ \"type\": \"Feature\", \"properties\": { \"yes\": \"no\", \"who\": 1, \"$$k\": \"$$v\" }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in1.json
|
||||
perl -e 'for ($$i = 0; $$i < 300000; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; print "{ \"type\": \"Feature\", \"properties\": { }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in2.json
|
||||
perl -e 'for ($$i = 0; $$i < 20; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; print "{ \"type\": \"Feature\", \"properties\": { }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in3.json
|
||||
perl -e 'for ($$i = 0; $$i < 20; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; $$v = rand(1); print "{ \"type\": \"Feature\", \"properties\": { }, \"tippecanoe\": { \"layer\": \"$$v\" }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in4.json
|
||||
echo -n "" > tests/parallel/empty1.json
|
||||
echo "" > tests/parallel/empty2.json
|
||||
./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-file.mbtiles tests/parallel/in[123].json tests/parallel/empty[12].json
|
||||
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-file.mbtiles tests/parallel/in[123].json tests/parallel/empty[12].json
|
||||
cat tests/parallel/in[123].json | ./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-pipe.mbtiles
|
||||
cat tests/parallel/in[123].json | ./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipe.mbtiles
|
||||
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipes.mbtiles <(cat tests/parallel/in1.json) <(cat tests/parallel/empty1.json) <(cat tests/parallel/empty2.json) <(cat tests/parallel/in2.json) /dev/null <(cat tests/parallel/in3.json)
|
||||
./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
|
||||
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
|
||||
cat tests/parallel/in[1234].json | ./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-pipe.mbtiles
|
||||
cat tests/parallel/in[1234].json | ./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipe.mbtiles
|
||||
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipes.mbtiles <(cat tests/parallel/in1.json) <(cat tests/parallel/empty1.json) <(cat tests/parallel/empty2.json) <(cat tests/parallel/in2.json) /dev/null <(cat tests/parallel/in3.json) <(cat tests/parallel/in4.json)
|
||||
./tippecanoe-decode tests/parallel/linear-file.mbtiles > tests/parallel/linear-file.json
|
||||
./tippecanoe-decode tests/parallel/parallel-file.mbtiles > tests/parallel/parallel-file.json
|
||||
./tippecanoe-decode tests/parallel/linear-pipe.mbtiles > tests/parallel/linear-pipe.json
|
||||
|
10
geometry.cpp
10
geometry.cpp
@ -699,7 +699,7 @@ drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long lon
|
||||
return out;
|
||||
}
|
||||
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int detail, int buffer) {
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer) {
|
||||
long long area = 1LL << (32 - z);
|
||||
long long clip_buffer = buffer * area / 256;
|
||||
|
||||
@ -785,7 +785,7 @@ drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double
|
||||
return out;
|
||||
}
|
||||
|
||||
drawvec clip_point(drawvec &geom, int z, int detail, long long buffer) {
|
||||
drawvec clip_point(drawvec &geom, int z, long long buffer) {
|
||||
drawvec out;
|
||||
|
||||
long long min = 0;
|
||||
@ -803,7 +803,7 @@ drawvec clip_point(drawvec &geom, int z, int detail, long long buffer) {
|
||||
return out;
|
||||
}
|
||||
|
||||
int quick_check(long long *bbox, int z, int detail, long long buffer) {
|
||||
int quick_check(long long *bbox, int z, long long buffer) {
|
||||
long long min = 0;
|
||||
long long area = 1LL << (32 - z);
|
||||
|
||||
@ -827,7 +827,7 @@ int quick_check(long long *bbox, int z, int detail, long long buffer) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool point_within_tile(long long x, long long y, int z, int detail, long long buffer) {
|
||||
bool point_within_tile(long long x, long long y, int z, long long buffer) {
|
||||
// No adjustment for buffer, because the point must be
|
||||
// strictly within the tile to appear exactly once
|
||||
|
||||
@ -836,7 +836,7 @@ bool point_within_tile(long long x, long long y, int z, int detail, long long bu
|
||||
return x >= 0 && y >= 0 && x < area && y < area;
|
||||
}
|
||||
|
||||
drawvec clip_lines(drawvec &geom, int z, int detail, long long buffer) {
|
||||
drawvec clip_lines(drawvec &geom, int z, long long buffer) {
|
||||
drawvec out;
|
||||
|
||||
long long min = 0;
|
||||
|
10
geometry.hpp
10
geometry.hpp
@ -56,15 +56,15 @@ typedef std::vector<draw> drawvec;
|
||||
drawvec decode_geometry(FILE *meta, long long *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y);
|
||||
void to_tile_scale(drawvec &geom, int z, int detail);
|
||||
drawvec remove_noop(drawvec geom, int type, int shift);
|
||||
drawvec clip_point(drawvec &geom, int z, int detail, long long buffer);
|
||||
drawvec clip_point(drawvec &geom, int z, long long buffer);
|
||||
drawvec clean_or_clip_poly(drawvec &geom, int z, int detail, int buffer, bool clip);
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int detail, int buffer);
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer);
|
||||
drawvec close_poly(drawvec &geom);
|
||||
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double *accum_area);
|
||||
drawvec clip_lines(drawvec &geom, int z, int detail, long long buffer);
|
||||
drawvec clip_lines(drawvec &geom, int z, long long buffer);
|
||||
drawvec stairstep(drawvec &geom, int z, int detail);
|
||||
bool point_within_tile(long long x, long long y, int z, int detail, long long buffer);
|
||||
int quick_check(long long *bbox, int z, int detail, long long buffer);
|
||||
bool point_within_tile(long long x, long long y, int z, long long buffer);
|
||||
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 reorder_lines(drawvec &geom);
|
||||
drawvec fix_polygon(drawvec &geom);
|
||||
|
146
tile.cpp
146
tile.cpp
@ -1171,6 +1171,82 @@ struct write_tile_args {
|
||||
const char *postfilter;
|
||||
};
|
||||
|
||||
bool clip_to_tile(serial_feature &sf, int z, long long buffer) {
|
||||
int quick = quick_check(sf.bbox, z, buffer);
|
||||
if (quick == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (z == 0) {
|
||||
if (sf.bbox[0] < 0 || sf.bbox[2] > 1LL << 32) {
|
||||
// If the geometry extends off the edge of the world, concatenate on another copy
|
||||
// shifted by 360 degrees, and then make sure both copies get clipped down to size.
|
||||
|
||||
size_t n = sf.geometry.size();
|
||||
|
||||
if (sf.bbox[0] < 0) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x + (1LL << 32), sf.geometry[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
if (sf.bbox[2] > 1LL << 32) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x - (1LL << 32), sf.geometry[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
sf.bbox[0] = 0;
|
||||
sf.bbox[2] = 1LL << 32;
|
||||
|
||||
quick = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Can't accept the quick check if guaranteeing no duplication, since the
|
||||
// overlap might have been in the buffer.
|
||||
if (quick != 1 || prevent[P_DUPLICATION]) {
|
||||
drawvec clipped;
|
||||
|
||||
// Do the clipping, even if we are going to include the whole feature,
|
||||
// so that we can know whether the feature itself, or only the feature's
|
||||
// bounding box, touches the tile.
|
||||
|
||||
if (sf.t == VT_LINE) {
|
||||
clipped = clip_lines(sf.geometry, z, buffer);
|
||||
}
|
||||
if (sf.t == VT_POLYGON) {
|
||||
clipped = simple_clip_poly(sf.geometry, z, buffer);
|
||||
}
|
||||
if (sf.t == VT_POINT) {
|
||||
clipped = clip_point(sf.geometry, z, buffer);
|
||||
}
|
||||
|
||||
clipped = remove_noop(clipped, sf.t, 0);
|
||||
|
||||
// Must clip at z0 even if we don't want clipping, to handle features
|
||||
// that are duplicated across the date line
|
||||
|
||||
if (prevent[P_DUPLICATION] && z != 0) {
|
||||
if (point_within_tile((sf.bbox[0] + sf.bbox[2]) / 2, (sf.bbox[1] + sf.bbox[3]) / 2, z, buffer)) {
|
||||
// sf.geometry is unchanged
|
||||
} else {
|
||||
sf.geometry.clear();
|
||||
}
|
||||
} else if (prevent[P_CLIPPING] && z != 0) {
|
||||
if (clipped.size() == 0) {
|
||||
sf.geometry.clear();
|
||||
} else {
|
||||
// sf.geometry is unchanged
|
||||
}
|
||||
} else {
|
||||
sf.geometry = clipped;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long long write_tile(FILE *geoms, long long *geompos_in, char *metabase, char *stringpool, int z, unsigned tx, unsigned ty, int detail, int min_detail, int basezoom, sqlite3 *outdb, double droprate, int buffer, const char *fname, FILE **geomfile, int minzoom, int maxzoom, double todo, volatile long long *along, long long alongminus, double gamma, int child_shards, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, volatile int *running, double simplification, std::vector<std::map<std::string, layermap_entry>> *layermaps, std::vector<std::vector<std::string>> *layer_unmaps, size_t pass, size_t passes, unsigned long long mingap, long long minextent, double fraction, const char *prefilter, const char *postfilter, write_tile_args *arg) {
|
||||
int line_detail;
|
||||
double merge_fraction = 1;
|
||||
@ -1270,78 +1346,10 @@ long long write_tile(FILE *geoms, long long *geompos_in, char *metabase, char *s
|
||||
|
||||
original_features++;
|
||||
|
||||
int quick = quick_check(sf.bbox, z, line_detail, buffer);
|
||||
if (quick == 0) {
|
||||
if (clip_to_tile(sf, z, buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z == 0) {
|
||||
if (sf.bbox[0] < 0 || sf.bbox[2] > 1LL << 32) {
|
||||
// If the geometry extends off the edge of the world, concatenate on another copy
|
||||
// shifted by 360 degrees, and then make sure both copies get clipped down to size.
|
||||
|
||||
size_t n = sf.geometry.size();
|
||||
|
||||
if (sf.bbox[0] < 0) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x + (1LL << 32), sf.geometry[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
if (sf.bbox[2] > 1LL << 32) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
sf.geometry.push_back(draw(sf.geometry[i].op, sf.geometry[i].x - (1LL << 32), sf.geometry[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
sf.bbox[0] = 0;
|
||||
sf.bbox[2] = 1LL << 32;
|
||||
|
||||
quick = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Can't accept the quick check if guaranteeing no duplication, since the
|
||||
// overlap might have been in the buffer.
|
||||
if (quick != 1 || prevent[P_DUPLICATION]) {
|
||||
drawvec clipped;
|
||||
|
||||
// Do the clipping, even if we are going to include the whole feature,
|
||||
// so that we can know whether the feature itself, or only the feature's
|
||||
// bounding box, touches the tile.
|
||||
|
||||
if (sf.t == VT_LINE) {
|
||||
clipped = clip_lines(sf.geometry, z, line_detail, buffer);
|
||||
}
|
||||
if (sf.t == VT_POLYGON) {
|
||||
clipped = simple_clip_poly(sf.geometry, z, line_detail, buffer);
|
||||
}
|
||||
if (sf.t == VT_POINT) {
|
||||
clipped = clip_point(sf.geometry, z, line_detail, buffer);
|
||||
}
|
||||
|
||||
clipped = remove_noop(clipped, sf.t, 0);
|
||||
|
||||
// Must clip at z0 even if we don't want clipping, to handle features
|
||||
// that are duplicated across the date line
|
||||
|
||||
if (prevent[P_DUPLICATION] && z != 0) {
|
||||
if (point_within_tile((sf.bbox[0] + sf.bbox[2]) / 2, (sf.bbox[1] + sf.bbox[3]) / 2, z, line_detail, buffer)) {
|
||||
// sf.geometry is unchanged
|
||||
} else {
|
||||
sf.geometry.clear();
|
||||
}
|
||||
} else if (prevent[P_CLIPPING] && z != 0) {
|
||||
if (clipped.size() == 0) {
|
||||
sf.geometry.clear();
|
||||
} else {
|
||||
// sf.geometry is unchanged
|
||||
}
|
||||
} else {
|
||||
sf.geometry = clipped;
|
||||
}
|
||||
}
|
||||
|
||||
if (sf.geometry.size() > 0) {
|
||||
unclipped_features++;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user