#include #include #include #include #include #include #include #include #include #include #include #include #include #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 // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames void latlon2tile(double lat, double lon, int zoom, unsigned int *x, unsigned int *y) { double lat_rad = lat * M_PI / 180; unsigned long long n = 1LL << zoom; *x = n * ((lon + 180) / 360); *y = n * (1 - (log(tan(lat_rad) + 1/cos(lat_rad)) / M_PI)) / 2; } void parse_geometry(int t, json_object *j, unsigned *bbox) { 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 || t == GEOM_MULTIPOINT) { printf(" moveto "); } else { printf(" lineto "); } } parse_geometry(within, j->array[i], bbox); } printf("]"); } else { if (j->length == 2 && j->array[0]->type == JSON_NUMBER && j->array[1]->type == JSON_NUMBER) { unsigned x, y; double lon = j->array[0]->number; double lat = j->array[1]->number; latlon2tile(lat, lon, 32, &x, &y); if (x < bbox[0]) { bbox[0] = x; } if (y < bbox[1]) { bbox[1] = y; } if (x > bbox[2]) { bbox[2] = x; } if (y > bbox[3]) { bbox[3] = y; } 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; } } } unsigned bbox[] = { UINT_MAX, UINT_MAX, 0, 0 }; printf("%d: ", mb_geometry[t]); parse_geometry(t, coordinates, bbox); printf("\n"); printf("bbox %x %x %x %x\n", bbox[0], bbox[1], bbox[2], bbox[3]); } 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; }