diff --git a/mvt.cpp b/mvt.cpp index 79e20c1..4a1b0dd 100644 --- a/mvt.cpp +++ b/mvt.cpp @@ -432,40 +432,11 @@ bool mvt_tile::decode(std::string &message, bool &was_compressed) { for (size_t i = 0; i < layer.features.size(); i++) { std::vector &geom = layer.features[i].geometry; - std::vector &attr = layer.features[i].node_attributes; - - for (size_t t = 0; t + 1 < attr.size(); t++) { - if (attr[t] >= layer.keys.size()) { - fprintf(stderr, "Out of bounds attribute reference %lu into %zu\n", attr[t], layer.keys.size()); - exit(EXIT_FAILURE); - } - - std::string key = layer.keys[attr[t]]; - - t++; - mvt_value const &val = layer.decode_property(attr, t); - - if (val.type != mvt_list) { - fprintf(stderr, "Expected node attribute to be a list\n"); - exit(EXIT_FAILURE); - } - - if (val.list_value.size() != geom.size()) { - fprintf(stderr, "Node attribute list size doesn't match geometry size\n"); - exit(EXIT_FAILURE); - } - - for (size_t g = 0; g < geom.size(); g++) { - geom[g].attribute = std::string("{\"") + quote(key) + "\":" + val.list_value[g].toString() + "}"; - } - } - - attr.clear(); + std::vector &elevations = layer.features[i].elevations; long current_elevation = elevation_scaling.offset; size_t off = 0; - std::vector &elevations = layer.features[i].elevations; if (elevations.size() != 0) { for (size_t j = 0; j < geom.size(); j++) { if (geom[j].op == mvt_moveto || geom[j].op == mvt_lineto) { diff --git a/mvt.hpp b/mvt.hpp index 8e34bc4..e16901a 100644 --- a/mvt.hpp +++ b/mvt.hpp @@ -31,7 +31,6 @@ struct mvt_geometry { long long y = 0; int /* mvt_operation */ op = 0; std::vector elevations; - std::string attribute; mvt_geometry(int op, long long x, long long y); mvt_geometry(int op, long long x, long long y, std::vector elevation); diff --git a/plugin.cpp b/plugin.cpp index 9bfc5dc..0b87c06 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -182,7 +182,7 @@ std::vector parse_layers(int fd, int z, unsigned x, unsigned y, std:: parse_geometry(t, coordinates, dv, VT_MOVETO, "Filter output", jp->line, j, false); if (attributes != NULL) { drawvec dv2; - parse_geometry(t, attributes, dv, VT_MOVETO, "Filter output", jp->line, j, true); + parse_geometry(t, attributes, dv2, VT_MOVETO, "Filter output", jp->line, j, true); merge_node_attributes(dv, dv2); } if (mb_geometry[t] == VT_POLYGON) { @@ -385,7 +385,7 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std:: parse_geometry(t, coordinates, dv, VT_MOVETO, "Filter output", jp->line, j, false); if (attributes != NULL) { drawvec dv2; - parse_geometry(t, attributes, dv, VT_MOVETO, "Filter output", jp->line, j, true); + parse_geometry(t, attributes, dv2, VT_MOVETO, "Filter output", jp->line, j, true); merge_node_attributes(dv, dv2); } if (mb_geometry[t] == VT_POLYGON) { diff --git a/read_json.cpp b/read_json.cpp index 7139600..3efc904 100644 --- a/read_json.cpp +++ b/read_json.cpp @@ -132,13 +132,13 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna void merge_node_attributes(drawvec &geom, drawvec &attributes) { if (attributes.size() != geom.size()) { - fprintf(stderr, "Geometry attributes don't match coordinates\n"); + fprintf(stderr, "Geometry attributes don't match coordinates: %zu attributes for %zu geometries\n", attributes.size(), geom.size()); exit(EXIT_FAILURE); } for (size_t i = 0; i < attributes.size(); i++) { if (geom[i].op != attributes[i].op) { - fprintf(stderr, "Geometry attributes don't match coordinates\n"); + fprintf(stderr, "Geometry attributes don't match coordinates: op %d vs %d\n", geom[i].op, attributes[i].op); exit(EXIT_FAILURE); } diff --git a/tests/node-attributes/out/-Ccat_-z0.json b/tests/node-attributes/out/-Ccat_-z0.json index 933cbe5..2df682b 100644 --- a/tests/node-attributes/out/-Ccat_-z0.json +++ b/tests/node-attributes/out/-Ccat_-z0.json @@ -12,25 +12,25 @@ }, "features": [ { "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ { "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.718590, 0 ], [ -122.431641, 37.788081, 0 ], [ -122.431641, 37.439974, 8192 ], [ -122.255859, 37.370157, 8192 ], [ -120.146484, 36.949892, 8192 ], [ -116.982422, 36.879621, 8192 ], [ -116.279297, 36.385913, 8192 ], [ -116.103516, 36.385913, 8192 ], [ -115.839844, 36.102376, 8192 ], [ -115.224609, 36.102376, 0 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.718590, 0 ], [ -122.431641, 37.788081, 0 ], [ -122.431641, 37.439974, 8192 ], [ -122.255859, 37.370157, 8192 ], [ -120.146484, 36.949892, 8192 ], [ -116.982422, 36.879621, 8192 ], [ -116.279297, 36.385913, 8192 ], [ -116.103516, 36.385913, 8192 ], [ -115.839844, 36.102376, 8192 ], [ -115.224609, 36.102376, 0 ] ], "attributes": [ {"time":"2015-06-23T22:02:16Z"}, {"time":"2015-06-23T22:30:35Z"}, {"time":"2015-06-23T22:34:00Z"}, {"time":"2015-06-23T22:35:21Z"}, {"time":"2015-06-23T22:49:15Z"}, {"time":"2015-06-23T23:09:16Z"}, {"time":"2015-06-23T23:15:42Z"}, {"time":"2015-06-23T23:16:40Z"}, {"time":"2015-06-23T23:20:11Z"}, {"time":"2015-06-23T23:27:27Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -115.224609, 36.102376, 0 ], [ -115.312500, 36.244273, 0 ], [ -113.291016, 36.315125, 8192 ], [ -110.917969, 37.230328, 8192 ], [ -108.193359, 37.718590, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -115.224609, 36.102376, 0 ], [ -115.312500, 36.244273, 0 ], [ -113.291016, 36.315125, 8192 ], [ -110.917969, 37.230328, 8192 ], [ -108.193359, 37.718590, 16384 ] ], "attributes": [ {"time":"2015-06-24T01:14:16Z"}, {"time":"2015-06-24T01:53:02Z"}, {"time":"2015-06-24T02:06:33Z"}, {"time":"2015-06-24T02:22:26Z"}, {"time":"2015-06-24T02:38:46Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.841797, 37.788081, 16384 ], [ -107.138672, 37.926868, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.841797, 37.788081, 16384 ], [ -107.138672, 37.926868, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:41:22Z"}, {"time":"2015-06-24T02:45:17Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.050781, 37.926868, 16384 ], [ -105.996094, 38.065392, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.050781, 37.926868, 16384 ], [ -105.996094, 38.065392, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:45:58Z"}, {"time":"2015-06-24T02:52:16Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.732422, 38.134557, 16384 ], [ -105.644531, 38.134557, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.732422, 38.134557, 16384 ], [ -105.644531, 38.134557, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:54:01Z"}, {"time":"2015-06-24T02:54:26Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.380859, 38.203655, 0 ], [ -103.974609, 38.134557, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.380859, 38.203655, 0 ], [ -103.974609, 38.134557, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:56:22Z"}, {"time":"2015-06-24T03:04:33Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -103.886719, 38.134557, 16384 ], [ -102.568359, 38.134557, 16384 ], [ -101.601562, 38.341656, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -103.886719, 38.134557, 16384 ], [ -102.568359, 38.134557, 16384 ], [ -101.601562, 38.341656, 16384 ] ], "attributes": [ {"time":"2015-06-24T03:05:09Z"}, {"time":"2015-06-24T03:13:01Z"}, {"time":"2015-06-24T03:18:59Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -101.425781, 38.341656, 16384 ], [ -100.634766, 38.548165, 16384 ], [ -97.207031, 39.027719, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -101.425781, 38.341656, 16384 ], [ -100.634766, 38.548165, 16384 ], [ -97.207031, 39.027719, 16384 ] ], "attributes": [ {"time":"2015-06-24T03:20:11Z"}, {"time":"2015-06-24T03:25:26Z"}, {"time":"2015-06-24T03:45:35Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -96.328125, 39.164141, 16384 ], [ -90.439453, 39.842286, 16384 ], [ -86.923828, 39.909736, 8192 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -96.328125, 39.164141, 16384 ], [ -90.439453, 39.842286, 16384 ], [ -86.923828, 39.909736, 8192 ] ], "attributes": [ {"time":"2015-06-24T03:51:05Z"}, {"time":"2015-06-24T04:25:18Z"}, {"time":"2015-06-24T04:45:15Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -86.923828, 39.909736, 0 ], [ -86.572266, 39.639538, 0 ], [ -86.308594, 39.774769, 0 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -86.923828, 39.909736, 0 ], [ -86.572266, 39.639538, 0 ], [ -86.308594, 39.774769, 0 ] ], "attributes": [ {"time":"2015-06-24T04:45:30Z"}, {"time":"2015-06-24T04:49:24Z"}, {"time":"2015-06-24T04:55:29Z"} ] } } ] } ] } ] } diff --git a/tests/node-attributes/out/-z0_-ccat.json b/tests/node-attributes/out/-z0_-ccat.json index 5aced32..bfe761d 100644 --- a/tests/node-attributes/out/-z0_-ccat.json +++ b/tests/node-attributes/out/-z0_-ccat.json @@ -12,25 +12,25 @@ }, "features": [ { "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ { "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.718590, 0 ], [ -122.431641, 37.788081, 0 ], [ -122.431641, 37.439974, 8192 ], [ -122.255859, 37.370157, 8192 ], [ -120.146484, 36.949892, 8192 ], [ -116.982422, 36.879621, 8192 ], [ -116.279297, 36.385913, 8192 ], [ -116.103516, 36.385913, 8192 ], [ -115.839844, 36.102376, 8192 ], [ -115.224609, 36.102376, 0 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.718590, 0 ], [ -122.431641, 37.788081, 0 ], [ -122.431641, 37.439974, 8192 ], [ -122.255859, 37.370157, 8192 ], [ -120.146484, 36.949892, 8192 ], [ -116.982422, 36.879621, 8192 ], [ -116.279297, 36.385913, 8192 ], [ -116.103516, 36.385913, 8192 ], [ -115.839844, 36.102376, 8192 ], [ -115.224609, 36.102376, 0 ] ], "attributes": [ {"time":"2015-06-23T22:02:16Z"}, {"time":"2015-06-23T22:30:35Z"}, {"time":"2015-06-23T22:34:00Z"}, {"time":"2015-06-23T22:35:21Z"}, {"time":"2015-06-23T22:49:15Z"}, {"time":"2015-06-23T23:09:16Z"}, {"time":"2015-06-23T23:15:42Z"}, {"time":"2015-06-23T23:16:40Z"}, {"time":"2015-06-23T23:20:11Z"}, {"time":"2015-06-23T23:27:27Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -115.224609, 36.102376, 0 ], [ -115.312500, 36.244273, 0 ], [ -113.291016, 36.315125, 8192 ], [ -110.917969, 37.230328, 8192 ], [ -108.193359, 37.718590, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -115.224609, 36.102376, 0 ], [ -115.312500, 36.244273, 0 ], [ -113.291016, 36.315125, 8192 ], [ -110.917969, 37.230328, 8192 ], [ -108.193359, 37.718590, 16384 ] ], "attributes": [ {"time":"2015-06-24T01:14:16Z"}, {"time":"2015-06-24T01:53:02Z"}, {"time":"2015-06-24T02:06:33Z"}, {"time":"2015-06-24T02:22:26Z"}, {"time":"2015-06-24T02:38:46Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.841797, 37.788081, 16384 ], [ -107.138672, 37.926868, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.841797, 37.788081, 16384 ], [ -107.138672, 37.926868, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:41:22Z"}, {"time":"2015-06-24T02:45:17Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.050781, 37.926868, 16384 ], [ -105.996094, 38.065392, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -107.050781, 37.926868, 16384 ], [ -105.996094, 38.065392, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:45:58Z"}, {"time":"2015-06-24T02:52:16Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.732422, 38.134557, 16384 ], [ -105.644531, 38.134557, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.732422, 38.134557, 16384 ], [ -105.644531, 38.134557, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:54:01Z"}, {"time":"2015-06-24T02:54:26Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.380859, 38.203655, 0 ], [ -103.974609, 38.134557, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -105.380859, 38.203655, 0 ], [ -103.974609, 38.134557, 16384 ] ], "attributes": [ {"time":"2015-06-24T02:56:22Z"}, {"time":"2015-06-24T03:04:33Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -103.886719, 38.134557, 16384 ], [ -102.568359, 38.134557, 16384 ], [ -101.601562, 38.341656, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -103.886719, 38.134557, 16384 ], [ -102.568359, 38.134557, 16384 ], [ -101.601562, 38.341656, 16384 ] ], "attributes": [ {"time":"2015-06-24T03:05:09Z"}, {"time":"2015-06-24T03:13:01Z"}, {"time":"2015-06-24T03:18:59Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -101.425781, 38.341656, 16384 ], [ -100.634766, 38.548165, 16384 ], [ -97.207031, 39.027719, 16384 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -101.425781, 38.341656, 16384 ], [ -100.634766, 38.548165, 16384 ], [ -97.207031, 39.027719, 16384 ] ], "attributes": [ {"time":"2015-06-24T03:20:11Z"}, {"time":"2015-06-24T03:25:26Z"}, {"time":"2015-06-24T03:45:35Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -96.328125, 39.164141, 16384 ], [ -90.439453, 39.842286, 16384 ], [ -86.923828, 39.909736, 8192 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -96.328125, 39.164141, 16384 ], [ -90.439453, 39.842286, 16384 ], [ -86.923828, 39.909736, 8192 ] ], "attributes": [ {"time":"2015-06-24T03:51:05Z"}, {"time":"2015-06-24T04:25:18Z"}, {"time":"2015-06-24T04:45:15Z"} ] } } , -{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -86.923828, 39.909736, 0 ], [ -86.572266, 39.639538, 0 ], [ -86.308594, 39.774769, 0 ] ] } } +{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [ -86.923828, 39.909736, 0 ], [ -86.572266, 39.639538, 0 ], [ -86.308594, 39.774769, 0 ] ], "attributes": [ {"time":"2015-06-24T04:45:30Z"}, {"time":"2015-06-24T04:49:24Z"}, {"time":"2015-06-24T04:55:29Z"} ] } } ] } ] } ] } diff --git a/write_json.cpp b/write_json.cpp index 85f4aae..bf74534 100644 --- a/write_json.cpp +++ b/write_json.cpp @@ -291,8 +291,10 @@ void print_val(mvt_feature const &feature, mvt_layer const &layer, mvt_value con state.json_write_stringified(s); } -static void quote(std::string &buf, std::string const &s) { +static std::string quote(std::string const &s) { + std::string buf; buf.push_back('"'); + for (size_t i = 0; i < s.size(); i++) { unsigned char ch = s[i]; @@ -307,12 +309,14 @@ static void quote(std::string &buf, std::string const &s) { buf.push_back(ch); } } + buf.push_back('"'); + return buf; } void stringify_val(std::string &out, mvt_feature const &feature, mvt_layer const &layer, mvt_value const &val, size_t vo) { if (val.type == mvt_string) { - quote(out, val.string_value); + out.append(quote(val.string_value)); } else if (val.type == mvt_int) { out.append(std::to_string(val.numeric_value.int_value)); } else if (val.type == mvt_double) { @@ -363,6 +367,40 @@ struct coordinate_writer { void (*function)(json_writer &state, lonlat const &p); }; +std::vector decode_node_attributes(mvt_feature const &feature, const mvt_layer &layer) { + std::vector const &geom = feature.geometry; + std::vector const &attr = feature.node_attributes; + std::vector out; + + for (size_t t = 0; t + 1 < attr.size(); t++) { + if (attr[t] >= layer.keys.size()) { + fprintf(stderr, "Out of bounds attribute reference %lu into %zu\n", attr[t], layer.keys.size()); + exit(EXIT_FAILURE); + } + + std::string key = layer.keys[attr[t]]; + + t++; + mvt_value const &val = layer.decode_property(attr, t); + + if (val.type != mvt_list) { + fprintf(stderr, "Expected node attribute to be a list\n"); + exit(EXIT_FAILURE); + } + + if (val.list_value.size() != geom.size()) { + fprintf(stderr, "Node attribute list size doesn't match geometry size\n"); + exit(EXIT_FAILURE); + } + + for (size_t g = 0; g < geom.size(); g++) { + out.push_back(std::string("{") + quote(key) + ":" + val.list_value[g].toString() + "}"); + } + } + + return out; +} + void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, bool dropped, unsigned long long index, long long sequence, long long extent, bool complain, json_writer &state) { for (size_t f = 0; f < layer.features.size(); f++) { mvt_feature const &feat = layer.features[f]; @@ -462,6 +500,8 @@ void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y std::vector ops; bool has_attributes = false; + std::vector attributes = decode_node_attributes(feat, layer); + for (size_t g = 0; g < feat.geometry.size(); g++) { int op = feat.geometry[g].op; long long px = feat.geometry[g].x; @@ -475,8 +515,8 @@ void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y double lat, lon; projection->unproject(wx, wy, 32, &lon, &lat); - ops.push_back(lonlat(op, lon, lat, px, py, feat.geometry[g].elevations, feat.geometry[g].attribute)); - if (feat.geometry[g].attribute.size() != 0) { + ops.push_back(lonlat(op, lon, lat, px, py, feat.geometry[g].elevations, attributes[g])); + if (attributes[g].size() != 0) { has_attributes = true; } } else {