diff --git a/Makefile b/Makefile index c754b69..ecf8dca 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ indent: TESTS = $(wildcard tests/*/out/*.json) SPACE = $(NULL) $(NULL) -test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test join-test-object +test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test join-object-test ./unit suffixes = json json.gz @@ -305,7 +305,7 @@ csv-test: cmp tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles.json rm -f tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles -join-test-object: +join-object-test: ./tippecanoe -z0 -f -o tests/object/out/before.mbtiles tests/object/in.json ./tile-join -f -o tests/object/out/after.mbtiles tests/object/out/before.mbtiles ./tippecanoe-decode -x generator tests/object/out/before.mbtiles | grep -v '"bounds"' > tests/object/out/before.mbtiles.jsontmp diff --git a/mvt.cpp b/mvt.cpp index b9cdbf6..8967f8c 100644 --- a/mvt.cpp +++ b/mvt.cpp @@ -13,6 +13,7 @@ #include "protozero/pbf_reader.hpp" #include "protozero/pbf_writer.hpp" #include "milo/dtoa_milo.h" +#include "jsonpull/jsonpull.h" int mvt_format = mvt_blake; @@ -607,6 +608,55 @@ size_t mvt_layer::tag_key(std::string const &key) { return ko; } +size_t tag_object(mvt_layer &layer, json_object *j) { + mvt_value tv; + + if (j->type == JSON_NUMBER) { + long long v; + if (is_integer(j->string, &v)) { + if (v >= 0) { + tv.type = mvt_int; + tv.numeric_value.int_value = v; + } else { + tv.type = mvt_sint; + tv.numeric_value.sint_value = v; + } + } else { + tv.type = mvt_double; + tv.numeric_value.double_value = atof(j->string); + } + } else if (j->type == JSON_TRUE) { + tv.type = mvt_bool; + tv.numeric_value.bool_value = 1; + } else if (j->type == JSON_FALSE) { + tv.type = mvt_bool; + tv.numeric_value.bool_value = 0; + } else if (j->type == JSON_STRING) { + tv.type = mvt_string; + tv.string_value = std::string(j->string); + } else if (j->type == JSON_NULL) { + tv.type = mvt_null; + tv.numeric_value.null_value = 0; + } else if (j->type == JSON_HASH) { + tv.type = mvt_hash; + tv.list_value = std::vector(); + + for (size_t i = 0; i < j->length; i++) { + tv.list_value.push_back(layer.tag_key(std::string(j->keys[i]->string))); + tv.list_value.push_back(tag_object(layer, j->values[i])); + } + } else if (j->type == JSON_ARRAY) { + tv.type = mvt_list; + tv.list_value = std::vector(); + + for (size_t i = 0; i < j->length; i++) { + tv.list_value.push_back(tag_object(layer, j->array[i])); + } + } + + return layer.tag_value(tv); +} + size_t mvt_layer::tag_value(mvt_value const &value) { size_t vo; @@ -624,8 +674,23 @@ size_t mvt_layer::tag_value(mvt_value const &value) { } void mvt_layer::tag(mvt_feature &feature, std::string key, mvt_value value) { - feature.tags.push_back(tag_key(key)); - feature.tags.push_back(tag_value(value)); + if (value.type == mvt_hash) { + json_pull *jp = json_begin_string((char *) value.string_value.c_str()); + json_object *jo = json_read_tree(jp); + if (jo == NULL) { + fprintf(stderr, "Internal error: failed to reconstruct JSON %s\n", value.string_value.c_str()); + exit(EXIT_FAILURE); + } + size_t ko = tag_key(key); + size_t vo = tag_object(*this, jo); + feature.tags.push_back(ko); + feature.tags.push_back(vo); + json_free(jo); + json_end(jp); + } else { + feature.tags.push_back(tag_key(key)); + feature.tags.push_back(tag_value(value)); + } } void mvt_layer::tag_v3(mvt_feature &feature, std::string key, mvt_value value) { diff --git a/tests/object/out/-Ccat_-z0.json b/tests/object/out/-Ccat_-z0.json new file mode 100644 index 0000000..8e901a5 --- /dev/null +++ b/tests/object/out/-Ccat_-z0.json @@ -0,0 +1,18 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "0.000000,0.000000,0.000000,0.000000", +"center": "0.000000,0.000000,0", +"description": "tests/object/out/-Ccat_-z0.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {\"compound\": \"Mixed\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"compound\",\"count\": 1,\"type\": \"mixed\",\"values\": [\"{\\\"string\\\":\\\"string\\\",\\\"number\\\":10,\\\"null\\\":null,\\\"true\\\":true,\\\"false\\\":false,\\\"array\\\":[\\\"string\\\",10,null,true,false,[1,2,3],{\\\"this\\\":\\\"that\\\"}],\\\"emptylist\\\":[],\\\"emptyhash\\\":{},\\\"nest\\\":{\\\"something\\\":\\\"else\\\"}}\"]}]}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/object/out/-Ccat_-z0.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { "compound": {"string":"string","number":10,"null":null,"true":true,"false":false,"array":["string",10,null,true,false,[1,2,3],{"this":"that"}],"emptylist":[],"emptyhash":{},"nest":{"something":"else"}} }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 0.000000 ] } } +] } +] } +] } diff --git a/tests/object/out/-z0_-ccat.json b/tests/object/out/-z0_-ccat.json new file mode 100644 index 0000000..b277633 --- /dev/null +++ b/tests/object/out/-z0_-ccat.json @@ -0,0 +1,18 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "0.000000,0.000000,0.000000,0.000000", +"center": "0.000000,0.000000,0", +"description": "tests/object/out/-z0_-ccat.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {\"compound\": \"Mixed\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"compound\",\"count\": 1,\"type\": \"mixed\",\"values\": [\"{\\\"string\\\":\\\"string\\\",\\\"number\\\":10,\\\"null\\\":null,\\\"true\\\":true,\\\"false\\\":false,\\\"array\\\":[\\\"string\\\",10,null,true,false,[1,2,3],{\\\"this\\\":\\\"that\\\"}],\\\"emptylist\\\":[],\\\"emptyhash\\\":{},\\\"nest\\\":{\\\"something\\\":\\\"else\\\"}}\"]}]}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/object/out/-z0_-ccat.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { "compound": {"string":"string","number":10,"null":null,"true":true,"false":false,"array":["string",10,null,true,false,[1,2,3],{"this":"that"}],"emptylist":[],"emptyhash":{},"nest":{"something":"else"}} }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 0.000000 ] } } +] } +] } +] } diff --git a/tile.cpp b/tile.cpp index 92f2bc9..7af49cb 100644 --- a/tile.cpp +++ b/tile.cpp @@ -199,55 +199,6 @@ mvt_value retrieve_string(long long off, char *stringpool, int *otype) { return stringified_to_mvt_value(type, s); } -size_t tag_object(mvt_layer &layer, json_object *j) { - mvt_value tv; - - if (j->type == JSON_NUMBER) { - long long v; - if (is_integer(j->string, &v)) { - if (v >= 0) { - tv.type = mvt_int; - tv.numeric_value.int_value = v; - } else { - tv.type = mvt_sint; - tv.numeric_value.sint_value = v; - } - } else { - tv.type = mvt_double; - tv.numeric_value.double_value = atof(j->string); - } - } else if (j->type == JSON_TRUE) { - tv.type = mvt_bool; - tv.numeric_value.bool_value = 1; - } else if (j->type == JSON_FALSE) { - tv.type = mvt_bool; - tv.numeric_value.bool_value = 0; - } else if (j->type == JSON_STRING) { - tv.type = mvt_string; - tv.string_value = std::string(j->string); - } else if (j->type == JSON_NULL) { - tv.type = mvt_null; - tv.numeric_value.null_value = 0; - } else if (j->type == JSON_HASH) { - tv.type = mvt_hash; - tv.list_value = std::vector(); - - for (size_t i = 0; i < j->length; i++) { - tv.list_value.push_back(layer.tag_key(std::string(j->keys[i]->string))); - tv.list_value.push_back(tag_object(layer, j->values[i])); - } - } else if (j->type == JSON_ARRAY) { - tv.type = mvt_list; - tv.list_value = std::vector(); - - for (size_t i = 0; i < j->length; i++) { - tv.list_value.push_back(tag_object(layer, j->array[i])); - } - } - - return layer.tag_value(tv); -} - void decode_meta(std::vector const &metakeys, std::vector const &metavals, char *stringpool, mvt_layer &layer, mvt_feature &feature, bool suppress_null) { size_t i; for (i = 0; i < metakeys.size(); i++) { @@ -255,27 +206,11 @@ void decode_meta(std::vector const &metakeys, std::vector mvt_value key = retrieve_string(metakeys[i], stringpool, NULL); mvt_value value = retrieve_string(metavals[i], stringpool, &otype); - if (value.type == mvt_hash) { - json_pull *jp = json_begin_string((char *) value.string_value.c_str()); - json_object *j = json_read_tree(jp); - if (j == NULL) { - fprintf(stderr, "Internal error: failed to reconstruct JSON %s\n", value.string_value.c_str()); - exit(EXIT_FAILURE); - } - // XXX blake tag - size_t ko = layer.tag_key(key.string_value); - size_t vo = tag_object(layer, j); - feature.tags.push_back(ko); - feature.tags.push_back(vo); - json_free(j); - json_end(jp); - } else { - if (!suppress_null || value.type != mvt_null) { - if (mvt_format == mvt_blake || mvt_format == mvt_blake_float) { - layer.tag_v3(feature, key.string_value, value); - } else { - layer.tag(feature, key.string_value, value); - } + if (!suppress_null || value.type != mvt_null) { + if (mvt_format == mvt_blake || mvt_format == mvt_blake_float) { + layer.tag_v3(feature, key.string_value, value); + } else { + layer.tag(feature, key.string_value, value); } } } @@ -2282,6 +2217,7 @@ long long write_tile(FILE *geoms, std::atomic *geompos_in, char *meta feature.has_id = layer_features[x].has_id; decode_meta(layer_features[x].keys, layer_features[x].values, layer_features[x].stringpool, layer, feature, true); + for (size_t a = 0; a < layer_features[x].full_keys.size(); a++) { serial_val sv = layer_features[x].full_values[a]; mvt_value v = stringified_to_mvt_value(sv.type, sv.s.c_str());