mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-01-22 12:28:03 +00:00
210 lines
5.2 KiB
C
210 lines
5.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include "jsonpull.h"
|
|
|
|
#define GEOM_POINT 0 /* array of positions */
|
|
#define GEOM_MULTIPOINT 1 /* array of arrays of positions */
|
|
#define GEOM_LINESTRING 2 /* array of arrays of positions */
|
|
#define GEOM_MULTILINESTRING 3 /* array of arrays of arrays of positions */
|
|
#define GEOM_POLYGON 4 /* array of arrays of arrays of positions */
|
|
#define GEOM_MULTIPOLYGON 5 /* array of arrays of arrays of arrays of positions */
|
|
#define GEOM_TYPES 6
|
|
|
|
#define MB_GEOM_POINT 1
|
|
#define MB_GEOM_LINE 2
|
|
#define MB_GEOM_POLYGON 3
|
|
|
|
char *geometry_names[GEOM_TYPES] = {
|
|
"Point",
|
|
"MultiPoint",
|
|
"LineString",
|
|
"MultiLineString",
|
|
"Polygon",
|
|
"MultiPolygon",
|
|
};
|
|
|
|
int geometry_within[GEOM_TYPES] = {
|
|
-1, /* point */
|
|
GEOM_POINT, /* multipoint */
|
|
GEOM_POINT, /* linestring */
|
|
GEOM_LINESTRING, /* multilinestring */
|
|
GEOM_LINESTRING, /* polygon */
|
|
GEOM_POLYGON, /* multipolygon */
|
|
};
|
|
|
|
int mb_geometry[GEOM_TYPES] = {
|
|
MB_GEOM_POINT,
|
|
MB_GEOM_POINT,
|
|
MB_GEOM_LINE,
|
|
MB_GEOM_LINE,
|
|
MB_GEOM_POLYGON,
|
|
MB_GEOM_POLYGON,
|
|
};
|
|
|
|
/* XXX */
|
|
#define META_STRING JSON_STRING
|
|
#define META_INTEGER JSON_NUMBER
|
|
#define META_BOOLEAN JSON_TRUE
|
|
|
|
void parse_geometry(int t, json_object *j) {
|
|
if (j == NULL || j->type != JSON_ARRAY) {
|
|
fprintf(stderr, "expected array for type %d\n", t);
|
|
return;
|
|
}
|
|
|
|
int within = geometry_within[t];
|
|
if (within >= 0) {
|
|
printf("[");
|
|
int i;
|
|
for (i = 0; i < j->length; i++) {
|
|
if (within == GEOM_POINT) {
|
|
if (i == 0) {
|
|
printf(" moveto ");
|
|
} else {
|
|
printf(" lineto ");
|
|
}
|
|
}
|
|
|
|
parse_geometry(within, j->array[i]);
|
|
}
|
|
printf("]");
|
|
} else {
|
|
if (j->length == 2 && j->array[0]->type == JSON_NUMBER && j->array[1]->type == JSON_NUMBER) {
|
|
printf(" %f,%f ", j->array[0]->number, j->array[1]->number);
|
|
} else {
|
|
fprintf(stderr, "malformed point");
|
|
}
|
|
}
|
|
|
|
if (t == GEOM_POLYGON) {
|
|
printf(" closepath ");
|
|
}
|
|
}
|
|
|
|
void read_json(FILE *f) {
|
|
json_pull *jp = json_begin_file(f);
|
|
|
|
while (1) {
|
|
json_object *j = json_read(jp);
|
|
if (j == NULL) {
|
|
if (jp->error != NULL) {
|
|
fprintf(stderr, "%d: %s\n", jp->line, jp->error);
|
|
}
|
|
|
|
json_free(jp->root);
|
|
break;
|
|
}
|
|
|
|
json_object *type = json_hash_get(j, "type");
|
|
if (type == NULL || type->type != JSON_STRING || strcmp(type->string, "Feature") != 0) {
|
|
continue;
|
|
}
|
|
|
|
json_object *geometry = json_hash_get(j, "geometry");
|
|
if (geometry == NULL) {
|
|
fprintf(stderr, "%d: feature with no geometry\n", jp->line);
|
|
goto next_feature;
|
|
}
|
|
|
|
json_object *geometry_type = json_hash_get(geometry, "type");
|
|
if (geometry_type == NULL || geometry_type->type != JSON_STRING) {
|
|
fprintf(stderr, "%d: geometry without type string\n", jp->line);
|
|
goto next_feature;
|
|
}
|
|
|
|
json_object *properties = json_hash_get(j, "properties");
|
|
if (properties == NULL || properties->type != JSON_HASH) {
|
|
fprintf(stderr, "%d: feature without properties hash\n", jp->line);
|
|
goto next_feature;
|
|
}
|
|
|
|
json_object *coordinates = json_hash_get(geometry, "coordinates");
|
|
if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
|
|
fprintf(stderr, "%d: feature without coordinates array\n", jp->line);
|
|
goto next_feature;
|
|
}
|
|
|
|
int t;
|
|
for (t = 0; t < GEOM_TYPES; t++) {
|
|
if (strcmp(geometry_type->string, geometry_names[t]) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (t >= GEOM_TYPES) {
|
|
fprintf(stderr, "%d: Can't handle geometry type %s\n", jp->line, geometry_type->string);
|
|
goto next_feature;
|
|
}
|
|
|
|
/* scope for variable-length arrays */
|
|
{
|
|
char *metakey[properties->length];
|
|
char *metaval[properties->length];
|
|
int metatype[properties->length];
|
|
int m = 0;
|
|
|
|
int i;
|
|
for (i = 0; i < properties->length; i++) {
|
|
if (properties->keys[i]->type == JSON_STRING) {
|
|
metakey[m] = properties->keys[i]->string;
|
|
|
|
if (properties->values[i] != NULL && properties->values[i]->type == JSON_STRING) {
|
|
metatype[m] = META_STRING;
|
|
metaval[m] = properties->values[i]->string;
|
|
m++;
|
|
} else if (properties->values[i] != NULL && properties->values[i]->type == JSON_NUMBER) {
|
|
metatype[m] = META_INTEGER;
|
|
metaval[m] = properties->values[i]->string;
|
|
m++;
|
|
} else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_TRUE || properties->values[i]->type == JSON_FALSE)) {
|
|
metatype[m] = META_BOOLEAN;
|
|
metaval[m] = properties->values[i]->string;
|
|
m++;
|
|
} else {
|
|
fprintf(stderr, "%d: Unsupported meta type\n", jp->line);
|
|
goto next_feature;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%d: ", mb_geometry[t]);
|
|
parse_geometry(t, coordinates);
|
|
printf("\n");
|
|
}
|
|
|
|
next_feature:
|
|
json_free(j);
|
|
|
|
/* XXX check for any non-features in the outer object */
|
|
}
|
|
|
|
json_end(jp);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc > 1) {
|
|
int i;
|
|
for (i = 1; 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 {
|
|
read_json(f);
|
|
fclose(f);
|
|
}
|
|
}
|
|
} else {
|
|
read_json(stdin);
|
|
}
|
|
return 0;
|
|
}
|