Preserve per-node attributes through feature filter pipelines

They now stay in array form until just before printing, rather
than being decoded into strings as part of tile deserialization
This commit is contained in:
Eric Fischer 2018-10-17 13:26:08 -07:00
parent 56bf3f4218
commit 4ce81bd587
7 changed files with 69 additions and 59 deletions

31
mvt.cpp
View File

@ -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<mvt_geometry> &geom = layer.features[i].geometry;
std::vector<unsigned long> &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<int> &elevations = layer.features[i].elevations;
long current_elevation = elevation_scaling.offset;
size_t off = 0;
std::vector<int> &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) {

View File

@ -31,7 +31,6 @@ struct mvt_geometry {
long long y = 0;
int /* mvt_operation */ op = 0;
std::vector<double> 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<double> elevation);

View File

@ -182,7 +182,7 @@ std::vector<mvt_layer> 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) {

View File

@ -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);
}

View File

@ -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"} ] } }
] }
] }
] }

View File

@ -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"} ] } }
] }
] }
] }

View File

@ -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<std::string> decode_node_attributes(mvt_feature const &feature, const mvt_layer &layer) {
std::vector<mvt_geometry> const &geom = feature.geometry;
std::vector<unsigned long> const &attr = feature.node_attributes;
std::vector<std::string> 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<lonlat> ops;
bool has_attributes = false;
std::vector<std::string> 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 {