Merge pull request #29 from mapbox/multilayer

Add multilayer support
This commit is contained in:
Eric Fischer
2015-04-10 11:03:36 -07:00
6 changed files with 440 additions and 354 deletions
+21 -5
View File
@@ -34,9 +34,10 @@ The easiest way to install tippecanoe on OSX is with [Homebrew](http://brew.sh/)
Usage Usage
----- -----
tippecanoe -o file.mbtiles [file.json] tippecanoe -o file.mbtiles [file.json ...]
If the file is not specified, it reads GeoJSON from the standard input. If no files are specified, it reads GeoJSON from the standard input.
If multiple files are specified, each is placed in its own layer.
The GeoJSON features need not be wrapped in a FeatureCollection. The GeoJSON features need not be wrapped in a FeatureCollection.
You can concatenate multiple GeoJSON features or files together, You can concatenate multiple GeoJSON features or files together,
@@ -46,18 +47,33 @@ it encounters.
Options Options
------- -------
* -l <i>name</i>: Layer name (default "file" if source is file.json) ### Naming
* -l <i>name</i>: Layer name (default "file" if source is file.json or output is file.mbtiles). Only works if there is only one layer.
* -n <i>name</i>: Human-readable name (default file.json) * -n <i>name</i>: Human-readable name (default file.json)
### File control
* -o <i>file</i>.mbtiles: Name the output file.
* -f: Delete the mbtiles file if it already exists instead of giving an error
### Zoom levels and resolution
* -z <i>zoom</i>: Base (maxzoom) zoom level (default 14) * -z <i>zoom</i>: Base (maxzoom) zoom level (default 14)
* -Z <i>zoom</i>: Lowest (minzoom) zoom level (default 0) * -Z <i>zoom</i>: Lowest (minzoom) zoom level (default 0)
* -d <i>detail</i>: Detail at base zoom level (default 26-basezoom, ~0.5m, for tile resolution of 4096 if -z14) * -d <i>detail</i>: Detail at base zoom level (default 26-basezoom, ~0.5m, for tile resolution of 4096 if -z14)
* -D <i>detail</i>: Detail at lower zoom levels (default 10, for tile resolution of 1024) * -D <i>detail</i>: Detail at lower zoom levels (default 10, for tile resolution of 1024)
* -b <i>pixels</i>: Buffer size where features are duplicated from adjacent tiles (default 5)
### Properties
* -x <i>name</i>: Exclude the named properties from all features * -x <i>name</i>: Exclude the named properties from all features
* -y <i>name</i>: Include the named properties in all features, excluding all those not explicitly named * -y <i>name</i>: Include the named properties in all features, excluding all those not explicitly named
* -X: Exclude all properties and encode only geometries * -X: Exclude all properties and encode only geometries
* -f: Delete the mbtiles file if it already exists instead of giving an error
### Point simplification
* -r <i>rate</i>: Rate at which dots are dropped at lower zoom levels (default 2.5) * -r <i>rate</i>: Rate at which dots are dropped at lower zoom levels (default 2.5)
* -b <i>pixels</i>: Buffer size where features are duplicated from adjacent tiles (default 5)
* -g <i>gamma</i>: Rate at which especially dense dots are dropped (default 0, for no effect). A gamma of 2 reduces the number of dots less than a pixel apart to the square root of their original number. * -g <i>gamma</i>: Rate at which especially dense dots are dropped (default 0, for no effect). A gamma of 2 reduces the number of dots less than a pixel apart to the square root of their original number.
Example Example
+261 -232
View File
@@ -58,41 +58,41 @@ int mb_geometry[GEOM_TYPES] = {
VT_POLYGON, VT_POLYGON,
}; };
size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, const char *fname, json_pull *source) { size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, const char *fname) {
size_t w = fwrite(ptr, size, nitems, stream); size_t w = fwrite(ptr, size, nitems, stream);
if (w != nitems) { if (w != nitems) {
fprintf(stderr, "%s:%d: Write to temporary file failed: %s\n", fname, source->line, strerror(errno)); fprintf(stderr, "%s: Write to temporary file failed: %s\n", fname, strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
return w; return w;
} }
void serialize_int(FILE *out, int n, long long *fpos, const char *fname, json_pull *source) { void serialize_int(FILE *out, int n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(int), 1, out, fname, source); fwrite_check(&n, sizeof(int), 1, out, fname);
*fpos += sizeof(int); *fpos += sizeof(int);
} }
void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname, json_pull *source) { void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(long long), 1, out, fname, source); fwrite_check(&n, sizeof(long long), 1, out, fname);
*fpos += sizeof(long long); *fpos += sizeof(long long);
} }
void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname, json_pull *source) { void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(signed char), 1, out, fname, source); fwrite_check(&n, sizeof(signed char), 1, out, fname);
*fpos += sizeof(signed char); *fpos += sizeof(signed char);
} }
void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname, json_pull *source) { void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(unsigned), 1, out, fname, source); fwrite_check(&n, sizeof(unsigned), 1, out, fname);
*fpos += sizeof(unsigned); *fpos += sizeof(unsigned);
} }
void serialize_string(FILE *out, const char *s, long long *fpos, const char *fname, json_pull *source) { void serialize_string(FILE *out, const char *s, long long *fpos, const char *fname) {
int len = strlen(s); int len = strlen(s);
serialize_int(out, len + 1, fpos, fname, source); serialize_int(out, len + 1, fpos, fname);
fwrite_check(s, sizeof(char), len, out, fname, source); fwrite_check(s, sizeof(char), len, out, fname);
fwrite_check("", sizeof(char), 1, out, fname, source); fwrite_check("", sizeof(char), 1, out, fname);
*fpos += len + 1; *fpos += len + 1;
} }
@@ -148,9 +148,9 @@ void parse_geometry(int t, json_object *j, unsigned *bbox, long long *fpos, FILE
} }
} }
serialize_byte(out, op, fpos, fname, source); serialize_byte(out, op, fpos, fname);
serialize_uint(out, x, fpos, fname, source); serialize_uint(out, x, fpos, fname);
serialize_uint(out, y, fpos, fname, source); serialize_uint(out, y, fpos, fname);
} else { } else {
fprintf(stderr, "%s:%d: malformed point\n", fname, source->line); fprintf(stderr, "%s:%d: malformed point\n", fname, source->line);
} }
@@ -158,7 +158,7 @@ void parse_geometry(int t, json_object *j, unsigned *bbox, long long *fpos, FILE
if (t == GEOM_POLYGON) { if (t == GEOM_POLYGON) {
if (*fpos != began) { if (*fpos != began) {
serialize_byte(out, VT_CLOSEPATH, fpos, fname, source); serialize_byte(out, VT_CLOSEPATH, fpos, fname);
} }
} }
} }
@@ -194,7 +194,7 @@ struct pool_val *deserialize_string(char **f, struct pool *p, int type) {
return ret; return ret;
} }
int traverse_zooms(int geomfd[4], off_t geom_size[4], char *metabase, unsigned *file_bbox, struct pool *file_keys, unsigned *midx, unsigned *midy, const char *layername, int maxzoom, int minzoom, sqlite3 *outdb, double droprate, int buffer, const char *fname, struct json_pull *jp, const char *tmpdir, double gamma) { int traverse_zooms(int geomfd[4], off_t geom_size[4], char *metabase, unsigned *file_bbox, struct pool **file_keys, unsigned *midx, unsigned *midy, char **layernames, int maxzoom, int minzoom, sqlite3 *outdb, double droprate, int buffer, const char *fname, const char *tmpdir, double gamma, int nlayers) {
int i; int i;
for (i = 0; i <= maxzoom; i++) { for (i = 0; i <= maxzoom; i++) {
long long most = 0; long long most = 0;
@@ -255,7 +255,7 @@ int traverse_zooms(int geomfd[4], off_t geom_size[4], char *metabase, unsigned *
// fprintf(stderr, "%d/%u/%u\n", z, x, y); // fprintf(stderr, "%d/%u/%u\n", z, x, y);
long long len = write_tile(&geom, metabase, file_bbox, z, x, y, z == maxzoom ? full_detail : low_detail, maxzoom, file_keys, layername, outdb, droprate, buffer, fname, jp, sub, minzoom, maxzoom, todo, geomstart, along, gamma); long long len = write_tile(&geom, metabase, file_bbox, z, x, y, z == maxzoom ? full_detail : low_detail, maxzoom, file_keys, layernames, outdb, droprate, buffer, fname, sub, minzoom, maxzoom, todo, geomstart, along, gamma, nlayers);
if (len < 0) { if (len < 0) {
return i - 1; return i - 1;
@@ -361,7 +361,7 @@ static void merge(struct merge *merges, int nmerges, unsigned char *map, FILE *f
} }
} }
int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, int minzoom, sqlite3 *outdb, struct pool *exclude, struct pool *include, int exclude_all, double droprate, int buffer, const char *tmpdir, double gamma) { int read_json(int argc, char **argv, char *fname, const char *layername, int maxzoom, int minzoom, sqlite3 *outdb, struct pool *exclude, struct pool *include, int exclude_all, double droprate, int buffer, const char *tmpdir, double gamma) {
int ret = EXIT_SUCCESS; int ret = EXIT_SUCCESS;
char metaname[strlen(tmpdir) + strlen("/meta.XXXXXXXX") + 1]; char metaname[strlen(tmpdir) + strlen("/meta.XXXXXXXX") + 1];
@@ -413,200 +413,227 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
unsigned file_bbox[] = { UINT_MAX, UINT_MAX, 0, 0 }; unsigned file_bbox[] = { UINT_MAX, UINT_MAX, 0, 0 };
unsigned midx = 0, midy = 0; unsigned midx = 0, midy = 0;
json_pull *jp = json_begin_file(f);
long long seq = 0; long long seq = 0;
while (1) { int nlayers = argc;
json_object *j = json_read(jp); if (nlayers == 0) {
if (j == NULL) { nlayers = 1;
if (jp->error != NULL) { }
fprintf(stderr, "%s:%d: %s\n", fname, jp->line, jp->error);
int n;
for (n = 0; n < nlayers; n++) {
json_pull *jp;
const char *reading;
FILE *fp;
if (n >= argc) {
reading = "standard input";
fp = stdin;
} else {
reading = argv[n];
fp = fopen(argv[n], "r");
if (fp == NULL) {
perror(argv[n]);
continue;
} }
json_free(jp->root);
break;
} }
json_object *type = json_hash_get(j, "type"); jp = json_begin_file(fp);
if (type == NULL || type->type != JSON_STRING || strcmp(type->string, "Feature") != 0) {
continue;
}
json_object *geometry = json_hash_get(j, "geometry"); while (1) {
if (geometry == NULL) { json_object *j = json_read(jp);
fprintf(stderr, "%s:%d: feature with no geometry\n", fname, jp->line); if (j == NULL) {
json_free(j); if (jp->error != NULL) {
continue; fprintf(stderr, "%s:%d: %s\n", reading, jp->line, jp->error);
} }
json_object *geometry_type = json_hash_get(geometry, "type"); json_free(jp->root);
if (geometry_type == NULL) { break;
static int warned = 0;
if (!warned) {
fprintf(stderr, "%s:%d: null geometry (additional not reported)\n", fname, jp->line);
warned = 1;
} }
json_free(j); json_object *type = json_hash_get(j, "type");
continue; if (type == NULL || type->type != JSON_STRING || strcmp(type->string, "Feature") != 0) {
} continue;
}
if (geometry_type->type != JSON_STRING) { json_object *geometry = json_hash_get(j, "geometry");
fprintf(stderr, "%s:%d: geometry without type\n", fname, jp->line); if (geometry == NULL) {
json_free(j); fprintf(stderr, "%s:%d: feature with no geometry\n", reading, jp->line);
continue; json_free(j);
} continue;
}
json_object *properties = json_hash_get(j, "properties"); json_object *geometry_type = json_hash_get(geometry, "type");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) { if (geometry_type == NULL) {
fprintf(stderr, "%s:%d: feature without properties hash\n", fname, jp->line); static int warned = 0;
json_free(j); if (!warned) {
continue; fprintf(stderr, "%s:%d: null geometry (additional not reported)\n", reading, jp->line);
} warned = 1;
}
json_object *coordinates = json_hash_get(geometry, "coordinates"); json_free(j);
if (coordinates == NULL || coordinates->type != JSON_ARRAY) { continue;
fprintf(stderr, "%s:%d: feature without coordinates array\n", fname, jp->line); }
json_free(j);
continue;
}
int t; if (geometry_type->type != JSON_STRING) {
for (t = 0; t < GEOM_TYPES; t++) { fprintf(stderr, "%s:%d: geometry without type\n", reading, jp->line);
if (strcmp(geometry_type->string, geometry_names[t]) == 0) { json_free(j);
break; continue;
} }
}
if (t >= GEOM_TYPES) {
fprintf(stderr, "%s:%d: Can't handle geometry type %s\n", fname, jp->line, geometry_type->string);
json_free(j);
continue;
}
{ json_object *properties = json_hash_get(j, "properties");
unsigned bbox[] = { UINT_MAX, UINT_MAX, 0, 0 }; if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "%s:%d: feature without properties hash\n", reading, jp->line);
json_free(j);
continue;
}
int nprop = 0; json_object *coordinates = json_hash_get(geometry, "coordinates");
if (properties->type == JSON_HASH) { if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
nprop = properties->length; fprintf(stderr, "%s:%d: feature without coordinates array\n", reading, jp->line);
json_free(j);
continue;
} }
long long metastart = metapos; int t;
char *metakey[nprop]; for (t = 0; t < GEOM_TYPES; t++) {
char *metaval[nprop]; if (strcmp(geometry_type->string, geometry_names[t]) == 0) {
int metatype[nprop]; break;
int m = 0; }
}
int i; if (t >= GEOM_TYPES) {
for (i = 0; i < nprop; i++) { fprintf(stderr, "%s:%d: Can't handle geometry type %s\n", reading, jp->line, geometry_type->string);
if (properties->keys[i]->type == JSON_STRING) { json_free(j);
if (exclude_all) { continue;
if (!is_pooled(include, properties->keys[i]->string, VT_STRING)) { }
{
unsigned bbox[] = { UINT_MAX, UINT_MAX, 0, 0 };
int nprop = 0;
if (properties->type == JSON_HASH) {
nprop = properties->length;
}
long long metastart = metapos;
char *metakey[nprop];
char *metaval[nprop];
int metatype[nprop];
int m = 0;
int i;
for (i = 0; i < nprop; i++) {
if (properties->keys[i]->type == JSON_STRING) {
if (exclude_all) {
if (!is_pooled(include, properties->keys[i]->string, VT_STRING)) {
continue;
}
} else if (is_pooled(exclude, properties->keys[i]->string, VT_STRING)) {
continue; continue;
} }
} else if (is_pooled(exclude, properties->keys[i]->string, VT_STRING)) {
continue;
}
metakey[m] = properties->keys[i]->string; metakey[m] = properties->keys[i]->string;
if (properties->values[i] != NULL && properties->values[i]->type == JSON_STRING) { if (properties->values[i] != NULL && properties->values[i]->type == JSON_STRING) {
metatype[m] = VT_STRING; metatype[m] = VT_STRING;
metaval[m] = properties->values[i]->string; metaval[m] = properties->values[i]->string;
m++; m++;
} else if (properties->values[i] != NULL && properties->values[i]->type == JSON_NUMBER) { } else if (properties->values[i] != NULL && properties->values[i]->type == JSON_NUMBER) {
metatype[m] = VT_NUMBER; metatype[m] = VT_NUMBER;
metaval[m] = properties->values[i]->string; metaval[m] = properties->values[i]->string;
m++; m++;
} else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_TRUE || properties->values[i]->type == JSON_FALSE)) { } else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_TRUE || properties->values[i]->type == JSON_FALSE)) {
metatype[m] = VT_BOOLEAN; metatype[m] = VT_BOOLEAN;
metaval[m] = properties->values[i]->string; metaval[m] = properties->values[i]->string;
m++; m++;
} else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_NULL)) { } else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_NULL)) {
; ;
} else { } else {
fprintf(stderr, "%s:%d: Unsupported property type for %s\n", fname, jp->line, properties->keys[i]->string); fprintf(stderr, "%s:%d: Unsupported property type for %s\n", reading, jp->line, properties->keys[i]->string);
json_free(j); json_free(j);
continue; continue;
}
} }
} }
}
serialize_int(metafile, m, &metapos, fname, jp); serialize_int(metafile, m, &metapos, fname);
for (i = 0; i < m; i++) { for (i = 0; i < m; i++) {
serialize_int(metafile, metatype[i], &metapos, fname, jp); serialize_int(metafile, metatype[i], &metapos, fname);
serialize_string(metafile, metakey[i], &metapos, fname, jp); serialize_string(metafile, metakey[i], &metapos, fname);
serialize_string(metafile, metaval[i], &metapos, fname, jp); serialize_string(metafile, metaval[i], &metapos, fname);
} }
long long geomstart = geompos; long long geomstart = geompos;
serialize_int(geomfile, mb_geometry[t], &geompos, fname, jp); serialize_byte(geomfile, mb_geometry[t], &geompos, fname);
serialize_long_long(geomfile, metastart, &geompos, fname, jp); serialize_byte(geomfile, n, &geompos, fname);
parse_geometry(t, coordinates, bbox, &geompos, geomfile, VT_MOVETO, fname, jp); serialize_long_long(geomfile, metastart, &geompos, fname);
serialize_byte(geomfile, VT_END, &geompos, fname, jp); parse_geometry(t, coordinates, bbox, &geompos, geomfile, VT_MOVETO, fname, jp);
serialize_byte(geomfile, VT_END, &geompos, fname);
/*
* Note that minzoom for lines is the dimension /*
* of the geometry in world coordinates, but * Note that minzoom for lines is the dimension
* for points is the lowest zoom level (in tiles, * of the geometry in world coordinates, but
* not in pixels) at which it should be drawn. * for points is the lowest zoom level (in tiles,
* * not in pixels) at which it should be drawn.
* So a line that is too small for, say, z8 *
* will have minzoom of 18 (if tile detail is 10), * So a line that is too small for, say, z8
* not 8. * will have minzoom of 18 (if tile detail is 10),
*/ * not 8.
int minzoom = 0; */
if (mb_geometry[t] == VT_LINE) { int minzoom = 0;
for (minzoom = 0; minzoom < 31; minzoom++) { if (mb_geometry[t] == VT_LINE) {
unsigned mask = 1 << (32 - (minzoom + 1)); for (minzoom = 0; minzoom < 31; minzoom++) {
unsigned mask = 1 << (32 - (minzoom + 1));
if (((bbox[0] & mask) != (bbox[2] & mask)) ||
((bbox[1] & mask) != (bbox[3] & mask))) { if (((bbox[0] & mask) != (bbox[2] & mask)) ||
break; ((bbox[1] & mask) != (bbox[3] & mask))) {
break;
}
} }
} } else if (mb_geometry[t] == VT_POINT) {
} else if (mb_geometry[t] == VT_POINT) { double r = ((double) rand()) / RAND_MAX;
double r = ((double) rand()) / RAND_MAX; if (r == 0) {
if (r == 0) { r = .00000001;
r = .00000001; }
minzoom = maxzoom - floor(log(r) / - log(droprate));
} }
minzoom = maxzoom - floor(log(r) / - log(droprate));
}
serialize_byte(geomfile, minzoom, &geompos, fname, jp); serialize_byte(geomfile, minzoom, &geompos, fname);
struct index index; struct index index;
index.start = geomstart; index.start = geomstart;
index.end = geompos; index.end = geompos;
index.index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2); index.index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2);
fwrite_check(&index, sizeof(struct index), 1, indexfile, fname, jp); fwrite_check(&index, sizeof(struct index), 1, indexfile, fname);
indexpos += sizeof(struct index); indexpos += sizeof(struct index);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (bbox[i] < file_bbox[i]) { if (bbox[i] < file_bbox[i]) {
file_bbox[i] = bbox[i]; file_bbox[i] = bbox[i];
}
} }
} for (i = 2; i < 4; i++) {
for (i = 2; i < 4; i++) { if (bbox[i] > file_bbox[i]) {
if (bbox[i] > file_bbox[i]) { file_bbox[i] = bbox[i];
file_bbox[i] = bbox[i]; }
} }
}
if (seq % 10000 == 0) { if (seq % 10000 == 0) {
fprintf(stderr, "Read %.2f million features\r", seq / 1000000.0); fprintf(stderr, "Read %.2f million features\r", seq / 1000000.0);
}
seq++;
} }
seq++;
json_free(j);
/* XXX check for any non-features in the outer object */
} }
json_free(j);
/* XXX check for any non-features in the outer object */ json_end(jp);
fclose(fp);
} }
json_end(jp);
fclose(metafile); fclose(metafile);
fclose(geomfile); fclose(geomfile);
fclose(indexfile); fclose(indexfile);
@@ -624,7 +651,7 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
} }
if (geomst.st_size == 0 || metast.st_size == 0) { if (geomst.st_size == 0 || metast.st_size == 0) {
fprintf(stderr, "%s: did not read any valid geometries\n", fname); fprintf(stderr, "did not read any valid geometries\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -634,38 +661,53 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct pool file_keys; struct pool file_keys1[nlayers];
pool_init(&file_keys, 0); struct pool *file_keys[nlayers];
int i;
for (i = 0; i < nlayers; i++) {
pool_init(&file_keys1[i], 0);
file_keys[i] = &file_keys1[i];
}
char trunc[strlen(fname) + 1]; char *layernames[nlayers];
if (layername == NULL) { for (i = 0; i < nlayers; i++) {
const char *ocp, *use = fname; if (argc <= 1 && layername != NULL) {
for (ocp = fname; *ocp; ocp++) { layernames[i] = strdup(layername);
if (*ocp == '/' && ocp[1] != '\0') { } else {
use = ocp + 1; char *src = argv[i];
if (argc < 1) {
src = fname;
} }
}
strcpy(trunc, use);
char *cp = strstr(trunc, ".json"); char *trunc = layernames[i] = malloc(strlen(src) + 1);
if (cp != NULL) { const char *ocp, *use = src;
*cp = '\0'; for (ocp = src; *ocp; ocp++) {
} if (*ocp == '/' && ocp[1] != '\0') {
cp = strstr(trunc, ".mbtiles"); use = ocp + 1;
if (cp != NULL) { }
*cp = '\0';
}
layername = trunc;
char *out = trunc;
for (cp = trunc; *cp; cp++) {
if (isalpha(*cp) || isdigit(*cp) || *cp == '_') {
*out++ = *cp;
} }
} strcpy(trunc, use);
*out = '\0';
printf("using layer name %s\n", trunc); char *cp = strstr(trunc, ".json");
if (cp != NULL) {
*cp = '\0';
}
cp = strstr(trunc, ".mbtiles");
if (cp != NULL) {
*cp = '\0';
}
layername = trunc;
char *out = trunc;
for (cp = trunc; *cp; cp++) {
if (isalpha(*cp) || isdigit(*cp) || *cp == '_') {
*out++ = *cp;
}
}
*out = '\0';
printf("using layer %d name %s\n", i, trunc);
}
} }
/* Sort the index by geometry */ /* Sort the index by geometry */
@@ -783,15 +825,15 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
geompos = 0; geompos = 0;
/* initial tile is 0/0/0 */ /* initial tile is 0/0/0 */
serialize_int(geomfile, 0, &geompos, fname, jp); serialize_int(geomfile, 0, &geompos, fname);
serialize_uint(geomfile, 0, &geompos, fname, jp); serialize_uint(geomfile, 0, &geompos, fname);
serialize_uint(geomfile, 0, &geompos, fname, jp); serialize_uint(geomfile, 0, &geompos, fname);
long long i; long long i;
long long sum = 0; long long sum = 0;
long long progress = 0; long long progress = 0;
for (i = 0; i < indexpos / sizeof(struct index); i++) { for (i = 0; i < indexpos / sizeof(struct index); i++) {
fwrite_check(geom_map + index_map[i].start, sizeof(char), index_map[i].end - index_map[i].start, geomfile, fname, jp); fwrite_check(geom_map + index_map[i].start, sizeof(char), index_map[i].end - index_map[i].start, geomfile, fname);
sum += index_map[i].end - index_map[i].start; sum += index_map[i].end - index_map[i].start;
long long p = 1000 * i / (indexpos / sizeof(struct index)); long long p = 1000 * i / (indexpos / sizeof(struct index));
@@ -802,7 +844,7 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
} }
/* end of tile */ /* end of tile */
serialize_int(geomfile, -2, &geompos, fname, jp); serialize_byte(geomfile, -2, &geompos, fname);
fclose(geomfile); fclose(geomfile);
} }
@@ -843,7 +885,7 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
fprintf(stderr, "%lld features, %lld bytes of geometry, %lld bytes of metadata\n", seq, (long long) geomst.st_size, (long long) metast.st_size); fprintf(stderr, "%lld features, %lld bytes of geometry, %lld bytes of metadata\n", seq, (long long) geomst.st_size, (long long) metast.st_size);
int written = traverse_zooms(fd, size, meta, file_bbox, &file_keys, &midx, &midy, layername, maxzoom, minzoom, outdb, droprate, buffer, fname, jp, tmpdir, gamma); int written = traverse_zooms(fd, size, meta, file_bbox, file_keys, &midx, &midy, layernames, maxzoom, minzoom, outdb, droprate, buffer, fname, tmpdir, gamma, nlayers);
if (maxzoom != written) { if (maxzoom != written) {
fprintf(stderr, "\n\n\n*** NOTE TILES ONLY COMPLETE THROUGH ZOOM %d ***\n\n\n", written); fprintf(stderr, "\n\n\n*** NOTE TILES ONLY COMPLETE THROUGH ZOOM %d ***\n\n\n", written);
@@ -883,9 +925,12 @@ int read_json(FILE *f, const char *fname, const char *layername, int maxzoom, in
midlon = maxlon; midlon = maxlon;
} }
mbtiles_write_metadata(outdb, fname, layername, minzoom, maxzoom, minlat, minlon, maxlat, maxlon, midlat, midlon, &file_keys); mbtiles_write_metadata(outdb, fname, layernames, minzoom, maxzoom, minlat, minlon, maxlat, maxlon, midlat, midlon, file_keys, nlayers); // XXX layers
pool_free_strings(&file_keys); for (i = 0; i < nlayers; i++) {
pool_free_strings(&file_keys1[i]);
free(layernames[i]);
}
return ret; return ret;
} }
@@ -925,7 +970,7 @@ int main(int argc, char **argv) {
break; break;
case 'Z': case 'Z':
minzoom = atoi(optarg); minzoom = atoi(optarg);
break; break;
case 'd': case 'd':
@@ -997,24 +1042,8 @@ int main(int argc, char **argv) {
sqlite3 *outdb = mbtiles_open(outdir, argv); sqlite3 *outdb = mbtiles_open(outdir, argv);
int ret = EXIT_SUCCESS; int ret = EXIT_SUCCESS;
if (argc == optind + 1) { ret = read_json(argc - optind, argv + optind, name ? name : outdir, layer, maxzoom, minzoom, outdb, &exclude, &include, exclude_all, droprate, buffer, tmpdir, gamma);
int i;
for (i = optind; i < argc; i++) {
FILE *f = fopen(argv[i], "r");
if (f == NULL) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
} else {
ret = read_json(f, name ? name : argv[i], layer, maxzoom, minzoom, outdb, &exclude, &include, exclude_all, droprate, buffer, tmpdir, gamma);
fclose(f);
}
}
} else if (argc > optind) {
fprintf(stderr, "%s: Only accepts one input file\n", argv[0]);
exit(EXIT_FAILURE);
} else {
ret = read_json(stdin, name ? name : outdir, layer, maxzoom, minzoom, outdb, &exclude, &include, exclude_all, droprate, buffer, tmpdir, gamma);
}
mbtiles_close(outdb, argv); mbtiles_close(outdb, argv);
return ret; return ret;
+28 -17
View File
@@ -107,7 +107,7 @@ static void aprintf(char **buf, const char *format, ...) {
free(tmp); free(tmp);
} }
void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, const char *layername, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, struct pool *fields) { void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, char **layername, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, struct pool **file_keys, int nlayers) {
char *sql, *err; char *sql, *err;
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('name', %Q);", fname); sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('name', %Q);", fname);
@@ -174,27 +174,38 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, const char *layer
sqlite3_free(sql); sqlite3_free(sql);
char *buf = strdup("{"); char *buf = strdup("{");
aprintf(&buf, "\"vector_layers\": [ { \"id\": \""); aprintf(&buf, "\"vector_layers\": [ ");
quote(&buf, layername);
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", minzoom, maxzoom);
struct pool_val *pv; int i;
for (pv = fields->head; pv != NULL; pv = pv->next) { for (i = 0; i < nlayers; i++) {
aprintf(&buf, "\""); if (i != 0) {
quote(&buf, pv->s);
if (pv->type == VT_NUMBER) {
aprintf(&buf, "\": \"Number\"");
} else {
aprintf(&buf, "\": \"String\"");
}
if (pv->next != NULL) {
aprintf(&buf, ", "); aprintf(&buf, ", ");
} }
aprintf(&buf, "{ \"id\": \"");
quote(&buf, layername[i]);
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", minzoom, maxzoom);
struct pool_val *pv;
for (pv = file_keys[i]->head; pv != NULL; pv = pv->next) {
aprintf(&buf, "\"");
quote(&buf, pv->s);
if (pv->type == VT_NUMBER) {
aprintf(&buf, "\": \"Number\"");
} else {
aprintf(&buf, "\": \"String\"");
}
if (pv->next != NULL) {
aprintf(&buf, ", ");
}
}
aprintf(&buf, "} }");
} }
aprintf(&buf, "} } ] }"); aprintf(&buf, " ] }");
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('json', %Q);", buf); sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('json', %Q);", buf);
if (sqlite3_exec(outdb, sql, NULL, NULL, &err) != SQLITE_OK) { if (sqlite3_exec(outdb, sql, NULL, NULL, &err) != SQLITE_OK) {
+1 -1
View File
@@ -2,6 +2,6 @@ sqlite3 *mbtiles_open(char *dbname, char **argv);
void mbtiles_write_tile(sqlite3 *outdb, int z, int tx, int ty, const char *data, int size); void mbtiles_write_tile(sqlite3 *outdb, int z, int tx, int ty, const char *data, int size);
void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, const char *layername, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, struct pool *fields); void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, char **layername, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, struct pool **file_keys, int nlayers);
void mbtiles_close(sqlite3 *outdb, char **argv); void mbtiles_close(sqlite3 *outdb, char **argv);
+123 -92
View File
@@ -214,52 +214,56 @@ void decode_meta(char **meta, struct pool *keys, struct pool *values, struct poo
} }
} }
mapnik::vector::tile create_tile(const char *layername, int line_detail, std::vector<coalesce> &features, long long *count, struct pool *keys, struct pool *values) { mapnik::vector::tile create_tile(char **layernames, int line_detail, std::vector<std::vector<coalesce> > &features, long long *count, struct pool **keys, struct pool **values, int nlayers) {
mapnik::vector::tile tile; mapnik::vector::tile tile;
mapnik::vector::tile_layer *layer = tile.add_layers();
layer->set_name(layername); int i;
layer->set_version(1); for (i = 0; i < nlayers; i++) {
layer->set_extent(1 << line_detail); mapnik::vector::tile_layer *layer = tile.add_layers();
unsigned x; layer->set_name(layernames[i]);
for (x = 0; x < features.size(); x++) { layer->set_version(1);
if (features[x].type == VT_LINE || features[x].type == VT_POLYGON) { layer->set_extent(1 << line_detail);
features[x].geom = remove_noop(features[x].geom, features[x].type);
unsigned x;
for (x = 0; x < features[i].size(); x++) {
if (features[i][x].type == VT_LINE || features[i][x].type == VT_POLYGON) {
features[i][x].geom = remove_noop(features[i][x].geom, features[i][x].type);
}
mapnik::vector::tile_feature *feature = layer->add_features();
if (features[i][x].type == VT_POINT) {
feature->set_type(mapnik::vector::tile::Point);
} else if (features[i][x].type == VT_LINE) {
feature->set_type(mapnik::vector::tile::LineString);
} else if (features[i][x].type == VT_POLYGON) {
feature->set_type(mapnik::vector::tile::Polygon);
} else {
feature->set_type(mapnik::vector::tile::Unknown);
}
to_feature(features[i][x].geom, feature);
*count += features[i][x].geom.size();
unsigned y;
for (y = 0; y < features[i][x].meta.size(); y++) {
feature->add_tags(features[i][x].meta[y]);
}
} }
mapnik::vector::tile_feature *feature = layer->add_features(); struct pool_val *pv;
for (pv = keys[i]->head; pv != NULL; pv = pv->next) {
if (features[x].type == VT_POINT) { layer->add_keys(pv->s, strlen(pv->s));
feature->set_type(mapnik::vector::tile::Point);
} else if (features[x].type == VT_LINE) {
feature->set_type(mapnik::vector::tile::LineString);
} else if (features[x].type == VT_POLYGON) {
feature->set_type(mapnik::vector::tile::Polygon);
} else {
feature->set_type(mapnik::vector::tile::Unknown);
} }
for (pv = values[i]->head; pv != NULL; pv = pv->next) {
mapnik::vector::tile_value *tv = layer->add_values();
to_feature(features[x].geom, feature); if (pv->type == VT_NUMBER) {
*count += features[x].geom.size(); tv->set_double_value(atof(pv->s));
} else {
unsigned y; tv->set_string_value(pv->s);
for (y = 0; y < features[x].meta.size(); y++) { }
feature->add_tags(features[x].meta[y]);
}
}
struct pool_val *pv;
for (pv = keys->head; pv != NULL; pv = pv->next) {
layer->add_keys(pv->s, strlen(pv->s));
}
for (pv = values->head; pv != NULL; pv = pv->next) {
mapnik::vector::tile_value *tv = layer->add_values();
if (pv->type == VT_NUMBER) {
tv->set_double_value(atof(pv->s));
} else {
tv->set_string_value(pv->s);
} }
} }
@@ -284,6 +288,7 @@ struct sll {
} }
}; };
#if 0
void evaluate(std::vector<coalesce> &features, char *metabase, struct pool *file_keys, const char *layername, int line_detail, long long orig) { void evaluate(std::vector<coalesce> &features, char *metabase, struct pool *file_keys, const char *layername, int line_detail, long long orig) {
std::vector<sll> options; std::vector<sll> options;
@@ -302,7 +307,7 @@ void evaluate(std::vector<coalesce> &features, char *metabase, struct pool *file
} }
std::vector<coalesce> empty; std::vector<coalesce> empty;
mapnik::vector::tile tile = create_tile(layername, line_detail, empty, &count, &keys, &values); mapnik::vector::tile tile = create_tile(layername, line_detail, empty, &count, &keys, &values, 1); // XXX layer
std::string s; std::string s;
std::string compressed; std::string compressed;
@@ -329,7 +334,7 @@ void evaluate(std::vector<coalesce> &features, char *metabase, struct pool *file
long long count = 0; long long count = 0;
std::vector<coalesce> empty; std::vector<coalesce> empty;
mapnik::vector::tile tile = create_tile(layername, line_detail, features, &count, &keys, &values); mapnik::vector::tile tile = create_tile(layername, line_detail, features, &count, &keys, &values, nlayers);
std::string s; std::string s;
std::string compressed; std::string compressed;
@@ -341,8 +346,9 @@ void evaluate(std::vector<coalesce> &features, char *metabase, struct pool *file
pool_free(&values); pool_free(&values);
pool_free(&keys); pool_free(&keys);
} }
#endif
long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, unsigned tx, unsigned ty, int detail, int basezoom, struct pool *file_keys, const char *layername, sqlite3 *outdb, double droprate, int buffer, const char *fname, json_pull *jp, FILE *geomfile[4], int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma) { long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, unsigned tx, unsigned ty, int detail, int basezoom, struct pool **file_keys, char **layernames, sqlite3 *outdb, double droprate, int buffer, const char *fname, FILE *geomfile[4], int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma, int nlayers) {
int line_detail; int line_detail;
static bool evaluated = false; static bool evaluated = false;
double oprogress = 0; double oprogress = 0;
@@ -352,10 +358,16 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
for (line_detail = detail; line_detail >= MIN_DETAIL || line_detail == detail; line_detail--) { for (line_detail = detail; line_detail >= MIN_DETAIL || line_detail == detail; line_detail--) {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
struct pool keys, values; struct pool keys1[nlayers], values1[nlayers];
pool_init(&keys, 0); struct pool *keys[nlayers], *values[nlayers];
pool_init(&values, 0); int i;
std::set<long long> dup; for (i = 0; i < nlayers; i++) {
pool_init(&keys1[i], 0);
pool_init(&values1[i], 0);
keys[i] = &keys1[i];
values[i] = &values1[i];
}
long long count = 0; long long count = 0;
//long long along = 0; //long long along = 0;
@@ -371,7 +383,10 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
double scale = (double) (1LL << (64 - 2 * (z + 8))); double scale = (double) (1LL << (64 - 2 * (z + 8)));
double gap = 0; double gap = 0;
std::vector<coalesce> features; std::vector<std::vector<coalesce> > features;
for (i = 0; i < nlayers; i++) {
features.push_back(std::vector<coalesce>());
}
int within[4] = { 0 }; int within[4] = { 0 };
long long geompos[4] = { 0 }; long long geompos[4] = { 0 };
@@ -379,12 +394,15 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
*geoms = og; *geoms = og;
while (1) { while (1) {
int t; signed char t;
deserialize_int(geoms, &t); deserialize_byte(geoms, &t);
if (t < 0) { if (t < 0) {
break; break;
} }
signed char layer;
deserialize_byte(geoms, &layer);
long long metastart; long long metastart;
deserialize_long_long(geoms, &metastart); deserialize_long_long(geoms, &metastart);
char *meta = metabase + metastart; char *meta = metabase + metastart;
@@ -448,9 +466,9 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
int quick2 = quick_check(bbox2, z + 1, line_detail, buffer); int quick2 = quick_check(bbox2, z + 1, line_detail, buffer);
if (quick2 != 0) { if (quick2 != 0) {
if (!within[j]) { if (!within[j]) {
serialize_int(geomfile[j], z + 1, &geompos[j], fname, jp); serialize_int(geomfile[j], z + 1, &geompos[j], fname);
serialize_uint(geomfile[j], tx * 2 + xo, &geompos[j], fname, jp); serialize_uint(geomfile[j], tx * 2 + xo, &geompos[j], fname);
serialize_uint(geomfile[j], ty * 2 + yo, &geompos[j], fname, jp); serialize_uint(geomfile[j], ty * 2 + yo, &geompos[j], fname);
within[j] = 1; within[j] = 1;
} }
@@ -462,20 +480,21 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
} }
//printf("type %d, meta %lld\n", t, metastart); //printf("type %d, meta %lld\n", t, metastart);
serialize_int(geomfile[j], t, &geompos[j], fname, jp); serialize_byte(geomfile[j], t, &geompos[j], fname);
serialize_long_long(geomfile[j], metastart, &geompos[j], fname, jp); serialize_byte(geomfile[j], layer, &geompos[j], fname);
serialize_long_long(geomfile[j], metastart, &geompos[j], fname);
for (unsigned u = 0; u < geom.size(); u++) { for (unsigned u = 0; u < geom.size(); u++) {
serialize_byte(geomfile[j], geom[u].op, &geompos[j], fname, jp); serialize_byte(geomfile[j], geom[u].op, &geompos[j], fname);
if (geom[u].op != VT_CLOSEPATH) { if (geom[u].op != VT_CLOSEPATH) {
serialize_uint(geomfile[j], geom[u].x + sx, &geompos[j], fname, jp); serialize_uint(geomfile[j], geom[u].x + sx, &geompos[j], fname);
serialize_uint(geomfile[j], geom[u].y + sy, &geompos[j], fname, jp); serialize_uint(geomfile[j], geom[u].y + sy, &geompos[j], fname);
} }
} }
serialize_byte(geomfile[j], VT_END, &geompos[j], fname, jp); serialize_byte(geomfile[j], VT_END, &geompos[j], fname);
serialize_byte(geomfile[j], feature_minzoom, &geompos[j], fname, jp); serialize_byte(geomfile[j], feature_minzoom, &geompos[j], fname);
} }
} }
} }
@@ -576,60 +595,70 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
c.metasrc = meta; c.metasrc = meta;
c.coalesced = false; c.coalesced = false;
decode_meta(&meta, &keys, &values, file_keys, &c.meta, NULL); decode_meta(&meta, keys[layer], values[layer], file_keys[layer], &c.meta, NULL);
features.push_back(c); features[layer].push_back(c);
} }
} }
int j; int j;
for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) {
if (within[j]) { if (within[j]) {
serialize_int(geomfile[j], -2, &geompos[j], fname, jp); serialize_byte(geomfile[j], -2, &geompos[j], fname);
within[j] = 0; within[j] = 0;
} }
} }
std::sort(features.begin(), features.end()); for (j = 0; j < nlayers; j++) {
std::sort(features[j].begin(), features[j].end());
std::vector<coalesce> out; std::vector<coalesce> out;
unsigned x; unsigned x;
for (x = 0; x < features.size(); x++) { for (x = 0; x < features[j].size(); x++) {
unsigned y = out.size() - 1; unsigned y = out.size() - 1;
if (out.size() > 0 && coalcmp(&features[x], &out[y]) < 0) { if (out.size() > 0 && coalcmp(&features[j][x], &out[y]) < 0) {
fprintf(stderr, "\nfeature out of order\n"); fprintf(stderr, "\nfeature out of order\n");
}
if (out.size() > 0 && out[y].geom.size() + features[x].geom.size() < 20000 && coalcmp(&features[x], &out[y]) == 0 && features[x].type != VT_POINT) {
unsigned z;
for (z = 0; z < features[x].geom.size(); z++) {
out[y].geom.push_back(features[x].geom[z]);
} }
out[y].coalesced = true;
} else {
out.push_back(features[x]);
}
}
features = out;
for (x = 0; x < features.size(); x++) { if (out.size() > 0 && out[y].geom.size() + features[j][x].geom.size() < 20000 && coalcmp(&features[j][x], &out[y]) == 0 && features[j][x].type != VT_POINT) {
if (features[x].coalesced && features[x].type == VT_LINE) { unsigned z;
features[x].geom = remove_noop(features[x].geom, features[x].type); for (z = 0; z < features[j][x].geom.size(); z++) {
features[x].geom = simplify_lines(features[x].geom, 32, 0); out[y].geom.push_back(features[j][x].geom[z]);
}
out[y].coalesced = true;
} else {
out.push_back(features[j][x]);
}
}
features[j] = out;
for (x = 0; x < features[j].size(); x++) {
if (features[j][x].coalesced && features[j][x].type == VT_LINE) {
features[j][x].geom = remove_noop(features[j][x].geom, features[j][x].type);
features[j][x].geom = simplify_lines(features[j][x].geom, 32, 0);
}
} }
} }
if (features.size() > 0) { long long totalsize = 0;
if (features.size() > 200000) { for (j = 0; j < nlayers; j++) {
fprintf(stderr, "tile %d/%u/%u has %lld features, >200000 \n", z, tx, ty, (long long) features.size()); totalsize += features[j].size();
}
if (totalsize > 0) {
if (totalsize > 200000) {
fprintf(stderr, "tile %d/%u/%u has %lld features, >200000 \n", z, tx, ty, totalsize);
fprintf(stderr, "Try using -z to set a higher base zoom level.\n"); fprintf(stderr, "Try using -z to set a higher base zoom level.\n");
return -1; return -1;
} }
mapnik::vector::tile tile = create_tile(layername, line_detail, features, &count, &keys, &values); mapnik::vector::tile tile = create_tile(layernames, line_detail, features, &count, keys, values, nlayers);
pool_free(&keys); int i;
pool_free(&values); for (i = 0; i < nlayers; i++) {
pool_free(&keys1[i]);
pool_free(&values1[i]);
}
std::string s; std::string s;
std::string compressed; std::string compressed;
@@ -642,7 +671,9 @@ long long write_tile(char **geoms, char *metabase, unsigned *file_bbox, int z, u
if (line_detail == MIN_DETAIL || !evaluated) { if (line_detail == MIN_DETAIL || !evaluated) {
evaluated = true; evaluated = true;
evaluate(features, metabase, file_keys, layername, line_detail, compressed.size()); #if 0
evaluate(features[0], metabase, file_keys[0], layername, line_detail, compressed.size()); // XXX layer
#endif
} }
} else { } else {
mbtiles_write_tile(outdb, z, tx, ty, compressed.data(), compressed.size()); mbtiles_write_tile(outdb, z, tx, ty, compressed.data(), compressed.size());
+6 -7
View File
@@ -12,13 +12,12 @@
#define VT_BOOLEAN 7 #define VT_BOOLEAN 7
struct pool; struct pool;
struct json_pull;
void serialize_int(FILE *out, int n, long long *fpos, const char *fname, struct json_pull *source); void serialize_int(FILE *out, int n, long long *fpos, const char *fname);
void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname, struct json_pull *source); void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname);
void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname, struct json_pull *source); void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname);
void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname, struct json_pull *source); void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname);
void serialize_string(FILE *out, const char *s, long long *fpos, const char *fname, struct json_pull *source); void serialize_string(FILE *out, const char *s, long long *fpos, const char *fname);
void deserialize_int(char **f, int *n); void deserialize_int(char **f, int *n);
void deserialize_long_long(char **f, long long *n); void deserialize_long_long(char **f, long long *n);
@@ -26,4 +25,4 @@ void deserialize_uint(char **f, unsigned *n);
void deserialize_byte(char **f, signed char *n); void deserialize_byte(char **f, signed char *n);
struct pool_val *deserialize_string(char **f, struct pool *p, int type); struct pool_val *deserialize_string(char **f, struct pool *p, int type);
long long write_tile(char **geom, char *metabase, unsigned *file_bbox, int z, unsigned x, unsigned y, int detail, int basezoom, struct pool *file_keys, const char *layername, sqlite3 *outdb, double droprate, int buffer, const char *fname, struct json_pull *jp, FILE *geomfile[4], int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma); long long write_tile(char **geom, char *metabase, unsigned *file_bbox, int z, unsigned x, unsigned y, int detail, int basezoom, struct pool **file_keys, char **layernames, sqlite3 *outdb, double droprate, int buffer, const char *fname, FILE *geomfile[4], int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma, int nlayers);