Merge pull request from mapbox/dateline

Handle features that cross the antimeridian
This commit is contained in:
Eric Fischer 2015-12-03 15:21:19 -08:00
commit bbcf9e1b3c
6 changed files with 61 additions and 32 deletions

@ -1,3 +1,8 @@
## 1.4.1
* Features that cross the antimeridian are split into two parts instead
of being partially lost off the edge
## 1.4.0
* More polygon correctness

@ -138,7 +138,7 @@ void serialize_string(FILE *out, const char *s, long long *fpos, const char *fna
*fpos += len + 1;
}
void parse_geometry(int t, json_object *j, unsigned *bbox, long long *fpos, FILE *out, int op, const char *fname, json_pull *source, long long *wx, long long *wy, int *initialized) {
void parse_geometry(int t, json_object *j, long long *bbox, long long *fpos, FILE *out, int op, const char *fname, json_pull *source, long long *wx, long long *wy, int *initialized) {
if (j == NULL || j->type != JSON_ARRAY) {
fprintf(stderr, "%s:%d: expected array for type %d\n", fname, source->line, t);
return;
@ -160,7 +160,7 @@ void parse_geometry(int t, json_object *j, unsigned *bbox, long long *fpos, FILE
}
} else {
if (j->length >= 2 && j->array[0]->type == JSON_NUMBER && j->array[1]->type == JSON_NUMBER) {
unsigned x, y;
long long x, y;
double lon = j->array[0]->number;
double lat = j->array[1]->number;
latlon2tile(lat, lon, 32, &x, &y);
@ -437,7 +437,7 @@ long long addpool(struct memfile *poolfile, struct memfile *treefile, char *s, c
return off;
}
int serialize_geometry(json_object *geometry, json_object *properties, const char *reading, json_pull *jp, long long *seq, long long *metapos, long long *geompos, long long *indexpos, struct pool *exclude, struct pool *include, int exclude_all, FILE *metafile, FILE *geomfile, FILE *indexfile, struct memfile *poolfile, struct memfile *treefile, const char *fname, int maxzoom, int layer, double droprate, unsigned *file_bbox, json_object *tippecanoe) {
int serialize_geometry(json_object *geometry, json_object *properties, const char *reading, json_pull *jp, long long *seq, long long *metapos, long long *geompos, long long *indexpos, struct pool *exclude, struct pool *include, int exclude_all, FILE *metafile, FILE *geomfile, FILE *indexfile, struct memfile *poolfile, struct memfile *treefile, const char *fname, int maxzoom, int layer, double droprate, long long *file_bbox, json_object *tippecanoe) {
json_object *geometry_type = json_hash_get(geometry, "type");
if (geometry_type == NULL) {
static int warned = 0;
@ -492,7 +492,7 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha
}
}
unsigned bbox[] = {UINT_MAX, UINT_MAX, 0, 0};
long long bbox[] = {UINT_MAX, UINT_MAX, 0, 0};
int nprop = 0;
if (properties != NULL && properties->type == JSON_HASH) {
@ -595,7 +595,13 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha
struct index index;
index.start = geomstart;
index.end = *geompos;
index.index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2);
// Calculate the center even if off the edge of the plane,
// and then mask to bring it back into the addressable area
long long midx = (bbox[0] / 2 + bbox[2] / 2) & ((1LL << 32) - 1);
long long midy = (bbox[1] / 2 + bbox[3] / 2) & ((1LL << 32) - 1);
index.index = encode(midx, midy);
fwrite_check(&index, sizeof(struct index), 1, indexfile, fname);
*indexpos += sizeof(struct index);
@ -620,7 +626,7 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha
return 1;
}
void parse_json(json_pull *jp, const char *reading, long long *seq, long long *metapos, long long *geompos, long long *indexpos, struct pool *exclude, struct pool *include, int exclude_all, FILE *metafile, FILE *geomfile, FILE *indexfile, struct memfile *poolfile, struct memfile *treefile, char *fname, int maxzoom, int layer, double droprate, unsigned *file_bbox) {
void parse_json(json_pull *jp, const char *reading, long long *seq, long long *metapos, long long *geompos, long long *indexpos, struct pool *exclude, struct pool *include, int exclude_all, FILE *metafile, FILE *geomfile, FILE *indexfile, struct memfile *poolfile, struct memfile *treefile, char *fname, int maxzoom, int layer, double droprate, long long *file_bbox) {
long long found_hashes = 0;
long long found_features = 0;
long long found_geometries = 0;
@ -814,7 +820,7 @@ int read_json(int argc, char **argv, char *fname, const char *layername, int max
memfile_write(treefile, &p, sizeof(struct stringpool));
}
unsigned file_bbox[] = {UINT_MAX, UINT_MAX, 0, 0};
long long file_bbox[] = {UINT_MAX, UINT_MAX, 0, 0};
unsigned midx = 0, midy = 0;
long long seq = 0;
@ -1159,6 +1165,24 @@ int read_json(int argc, char **argv, char *fname, const char *layername, int max
midlat = (maxlat + minlat) / 2;
midlon = (maxlon + minlon) / 2;
// If the bounding box extends off the plane on either side,
// a feature wrapped across the date line, so the width of the
// bounding box is the whole world.
if (file_bbox[0] < 0) {
file_bbox[0] = 0;
file_bbox[2] = (1LL << 32) - 1;
}
if (file_bbox[2] > (1LL << 32) - 1) {
file_bbox[0] = 0;
file_bbox[2] = (1LL << 32) - 1;
}
if (file_bbox[1] < 0) {
file_bbox[1] = 0;
}
if (file_bbox[3] < (1LL << 32) - 1) {
file_bbox[3] = (1LL << 32) - 1;
}
tile2latlon(file_bbox[0], file_bbox[1], 32, &maxlat, &minlon);
tile2latlon(file_bbox[2], file_bbox[3], 32, &minlat, &maxlon);

@ -2,39 +2,19 @@
#include "projection.h"
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
void latlon2tile(double lat, double lon, int zoom, unsigned int *x, unsigned int *y) {
void latlon2tile(double lat, double lon, int zoom, long long *x, long long *y) {
double lat_rad = lat * M_PI / 180;
unsigned long long n = 1LL << zoom;
long long llx = n * ((lon + 180) / 360);
long long lly = n * (1 - (log(tan(lat_rad) + 1 / cos(lat_rad)) / M_PI)) / 2;
if (lat >= 85.0511) {
lly = 0;
}
if (lat <= -85.0511) {
lly = n - 1;
}
if (llx < 0) {
llx = 0;
}
if (lly < 0) {
lly = 0;
}
if (llx >= n) {
llx = n - 1;
}
if (lly >= n) {
lly = n - 1;
}
*x = llx;
*y = lly;
}
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
void tile2latlon(unsigned int x, unsigned int y, int zoom, double *lat, double *lon) {
void tile2latlon(long long x, long long y, int zoom, double *lat, double *lon) {
unsigned long long n = 1LL << zoom;
*lon = 360.0 * x / n - 180.0;
*lat = atan(sinh(M_PI * (1 - 2.0 * y / n))) * 180.0 / M_PI;

@ -1,4 +1,4 @@
void latlon2tile(double lat, double lon, int zoom, unsigned int *x, unsigned int *y);
void tile2latlon(unsigned int x, unsigned int y, int zoom, double *lat, double *lon);
void latlon2tile(double lat, double lon, int zoom, long long *x, long long *y);
void tile2latlon(long long x, long long y, int zoom, double *lat, double *lon);
unsigned long long encode(unsigned int wx, unsigned int wy);
void decode(unsigned long long index, unsigned *wx, unsigned *wy);

20
tile.cc

@ -544,6 +544,26 @@ long long write_tile(char **geoms, char *metabase, char *stringpool, int z, unsi
continue;
}
if (z == 0) {
if (bbox[0] < 0 || 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.
unsigned n = geom.size();
for (unsigned i = 0; i < n; i++) {
geom.push_back(draw(geom[i].op, geom[i].x - (1LL << 32), geom[i].y));
}
for (unsigned i = 0; i < n; i++) {
geom.push_back(draw(geom[i].op, geom[i].x + (1LL << 32), geom[i].y));
}
bbox[0] = 0;
bbox[2] = 1LL << 32;
quick = -1;
}
}
if (quick != 1) {
if (t == VT_LINE) {
geom = clip_lines(geom, z, line_detail, buffer);

@ -1 +1 @@
#define VERSION "tippecanoe v1.4.0\n"
#define VERSION "tippecanoe v1.4.1\n"