From 120809b0042d698de29a17b47bc849ea585474f8 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 26 Sep 2014 17:07:52 -0700 Subject: [PATCH] Clip large LineString features down to the bounds of the tile --- Makefile | 2 +- clip.c | 9 ++++++++- tile.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4b9b26d9..deea5818 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ vector_tile.pb.cc vector_tile.pb.h: vector_tile.proto PG= -tippecanoe: geojson.o jsonpull.o vector_tile.pb.o tile.o +tippecanoe: geojson.o jsonpull.o vector_tile.pb.o tile.o clip.o g++ $(PG) -O3 -g -Wall -o $@ $^ -lm -lz -lprotobuf-lite -lsqlite3 libjsonpull.a: jsonpull.o diff --git a/clip.c b/clip.c index 8c552e27..d795554f 100644 --- a/clip.c +++ b/clip.c @@ -28,6 +28,7 @@ int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymi int outcode0 = computeOutCode(*x0, *y0, xmin, ymin, xmax, ymax); int outcode1 = computeOutCode(*x1, *y1, xmin, ymin, xmax, ymax); int accept = 0; + int changed = 0; while (1) { if (!(outcode0 | outcode1)) { // Bitwise OR is 0. Trivially accept and get out of loop @@ -65,13 +66,19 @@ int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymi *x0 = x; *y0 = y; outcode0 = computeOutCode(*x0, *y0, xmin, ymin, xmax, ymax); + changed = 1; } else { *x1 = x; *y1 = y; outcode1 = computeOutCode(*x1, *y1, xmin, ymin, xmax, ymax); + changed = 1; } } } - return accept; + if (accept == 0) { + return 0; + } else { + return changed + 1; + } } diff --git a/tile.cc b/tile.cc index 6e280366..b587e586 100644 --- a/tile.cc +++ b/tile.cc @@ -13,6 +13,7 @@ extern "C" { #include "tile.h" + #include "clip.h" } #define CMD_BITS 3 @@ -340,6 +341,58 @@ void douglas_peucker(struct draw *geom, int n, double e) { } } +int clip_lines(struct draw *geom, int n, int z, int detail) { + struct draw tmp[n * 3]; + int out = 0; + int i; + + for (i = 0; i < n; i++) { + if (i - 1 >= 0 && (geom[i - 1].op == VT_MOVETO || geom[i - 1].op == VT_LINETO) && geom[i].op == VT_LINETO) { + double x1 = geom[i - 1].x; + double y1 = geom[i - 1].y; + + double x2 = geom[i - 0].x; + double y2 = geom[i - 0].y; + + unsigned area = 0xFFFFFFFF; + if (z != 0) { + area = 1 << (32 - z); + } + + int c = clip(&x1, &y1, &x2, &y2, 0, 0, area, area); + + if (c > 1) { // clipped + tmp[out].op = VT_MOVETO; + tmp[out].x = x1; + tmp[out].y = y1; + out++; + + tmp[out].op = VT_LINETO; + tmp[out].x = x2; + tmp[out].y = y2; + out++; + + tmp[out].op = VT_MOVETO; + tmp[out].x = geom[i].x; + tmp[out].y = geom[i].y; + out++; + } else if (c == 1) { // unchanged + tmp[out++] = geom[i]; + } else { // clipped away entirely + tmp[out].op = VT_MOVETO; + tmp[out].op = geom[i].x; + tmp[out].op = geom[i].y; + out++; + } + } else { + tmp[out++] = geom[i]; + } + } + + memcpy(geom, tmp, out * sizeof(struct draw)); + return out; +} + int simplify_lines(struct draw *geom, int n, int z, int detail) { int res = 1 << (32 - detail - z); @@ -442,6 +495,10 @@ long long write_tile(struct index *start, struct index *end, char *metabase, uns deserialize_int(&meta, &t); decode_feature(&meta, geom, z, tx, ty, detail); + if (t == VT_LINE) { + len = clip_lines(geom, len, z, detail); + } + if (t == VT_LINE || t == VT_POLYGON) { len = simplify_lines(geom, len, z, detail); }