Support per-feature minzoom and maxzoom in geobuf

This commit is contained in:
Eric Fischer 2017-08-30 11:44:57 -07:00
parent 607ea6c643
commit 5665d08745
5 changed files with 128 additions and 24 deletions

View File

@ -9,6 +9,7 @@
#include "protozero/pbf_reader.hpp" #include "protozero/pbf_reader.hpp"
#include "protozero/pbf_writer.hpp" #include "protozero/pbf_writer.hpp"
#include "milo/dtoa_milo.h" #include "milo/dtoa_milo.h"
#include "jsonpull/jsonpull.h"
#define POINT 0 #define POINT 0
#define MULTIPOINT 1 #define MULTIPOINT 1
@ -41,7 +42,7 @@ serial_val readValue(protozero::pbf_reader &pbf, std::vector<std::string> &keys)
case 4: case 4:
sv.type = mvt_double; sv.type = mvt_double;
sv.s = std::to_string(- (long long) pbf.get_uint64()); sv.s = std::to_string(-(long long) pbf.get_uint64());
break; break;
case 5: case 5:
@ -226,8 +227,9 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
long long id = 0; long long id = 0;
bool has_id = false; bool has_id = false;
std::vector<serial_val> values; std::vector<serial_val> values;
std::vector<size_t> properties;
int type = 0; int type = 0;
serial_feature sf;
std::map<std::string, serial_val> other;
while (pbf.next()) { while (pbf.next()) {
switch (pbf.tag()) { switch (pbf.tag()) {
@ -259,10 +261,53 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
} }
case 14: { case 14: {
std::vector<size_t> properties;
auto pi = pbf.get_packed_uint32(); auto pi = pbf.get_packed_uint32();
for (auto it = pi.first; it != pi.second; ++it) { for (auto it = pi.first; it != pi.second; ++it) {
properties.push_back(*it); properties.push_back(*it);
} }
for (size_t i = 0; i + 1 < properties.size(); i += 2) {
if (properties[i] >= keys.size()) {
fprintf(stderr, "Out of bounds key: %zu in %zu\n", properties[i], keys.size());
exit(EXIT_FAILURE);
}
if (properties[i + 1] >= values.size()) {
fprintf(stderr, "Out of bounds value: %zu in %zu\n", properties[i + 1], values.size());
exit(EXIT_FAILURE);
}
sf.full_keys.push_back(keys[properties[i]]);
sf.full_values.push_back(values[properties[i + 1]]);
}
values.clear();
break;
}
case 15: {
std::vector<size_t> misc;
auto pi = pbf.get_packed_uint32();
for (auto it = pi.first; it != pi.second; ++it) {
misc.push_back(*it);
}
for (size_t i = 0; i + 1 < misc.size(); i += 2) {
if (misc[i] >= keys.size()) {
fprintf(stderr, "Out of bounds key: %zu in %zu\n", misc[i], keys.size());
exit(EXIT_FAILURE);
}
if (misc[i + 1] >= values.size()) {
fprintf(stderr, "Out of bounds value: %zu in %zu\n", misc[i + 1], values.size());
exit(EXIT_FAILURE);
}
other.insert(std::pair<std::string, serial_val>(keys[misc[i]], values[misc[i + 1]]));
}
values.clear();
break; break;
} }
@ -271,7 +316,6 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
} }
} }
serial_feature sf;
sf.layer = layer; sf.layer = layer;
sf.layername = layername; sf.layername = layername;
sf.segment = 0; // single thread sf.segment = 0; // single thread
@ -283,24 +327,31 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
sf.seq = (*sst->layer_seq); sf.seq = (*sst->layer_seq);
sf.geometry = dv; sf.geometry = dv;
sf.t = type; sf.t = type;
for (size_t i = 0; i + 1 < properties.size(); i += 2) {
if (properties[i] >= keys.size()) {
fprintf(stderr, "Out of bounds key: %zu in %zu\n", properties[i], keys.size());
exit(EXIT_FAILURE);
}
if (properties[i + 1] >= values.size()) {
fprintf(stderr, "Out of bounds value: %zu in %zu\n", properties[i + 1], values.size());
exit(EXIT_FAILURE);
}
sf.full_keys.push_back(keys[properties[i]]);
sf.full_values.push_back(values[properties[i + 1]]);
}
sf.m = sf.full_values.size(); sf.m = sf.full_values.size();
auto tip = other.find("tippecanoe");
if (tip != other.end()) {
json_pull *jp = json_begin_string(tip->second.s.c_str());
json_object *o = json_read_tree(jp);
if (o != NULL) {
json_object *min = json_hash_get(o, "minzoom");
if (min != NULL && (min->type == JSON_STRING || min->type == JSON_NUMBER)) {
sf.has_tippecanoe_minzoom = true;
sf.tippecanoe_minzoom = atoi(min->string);
}
json_object *max = json_hash_get(o, "maxzoom");
if (max != NULL && (max->type == JSON_STRING || max->type == JSON_NUMBER)) {
sf.has_tippecanoe_maxzoom = true;
sf.tippecanoe_maxzoom = atoi(max->string);
}
}
json_free(o);
json_end(jp);
}
serialize_feature(sst, sf); serialize_feature(sst, sf);
} }

View File

@ -69,7 +69,7 @@ json_pull *json_begin_file(FILE *f) {
} }
static ssize_t read_string(json_pull *j, char *buffer, size_t n) { static ssize_t read_string(json_pull *j, char *buffer, size_t n) {
char *cp = j->source; const char *cp = j->source;
size_t out = 0; size_t out = 0;
while (out < n && cp[out] != '\0') { while (out < n && cp[out] != '\0') {
@ -77,12 +77,12 @@ static ssize_t read_string(json_pull *j, char *buffer, size_t n) {
out++; out++;
} }
j->source = cp + out; j->source = (void *) (cp + out);
return out; return out;
} }
json_pull *json_begin_string(char *s) { json_pull *json_begin_string(const char *s) {
return json_begin(read_string, s); return json_begin(read_string, (void *) s);
} }
void json_end(json_pull *p) { void json_end(json_pull *p) {

View File

@ -56,7 +56,7 @@ typedef struct json_pull {
} json_pull; } json_pull;
json_pull *json_begin_file(FILE *f); json_pull *json_begin_file(FILE *f);
json_pull *json_begin_string(char *s); json_pull *json_begin_string(const char *s);
json_pull *json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source); json_pull *json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source);
void json_end(json_pull *p); void json_end(json_pull *p);

52
mvt.cpp
View File

@ -11,6 +11,7 @@
#include "protozero/varint.hpp" #include "protozero/varint.hpp"
#include "protozero/pbf_reader.hpp" #include "protozero/pbf_reader.hpp"
#include "protozero/pbf_writer.hpp" #include "protozero/pbf_writer.hpp"
#include "milo/dtoa_milo.h"
mvt_geometry::mvt_geometry(int nop, long long nx, long long ny) { mvt_geometry::mvt_geometry(int nop, long long nx, long long ny) {
this->op = nop; this->op = nop;
@ -394,6 +395,57 @@ bool mvt_value::operator<(const mvt_value &o) const {
return false; return false;
} }
static std::string quote(std::string const &s) {
std::string buf;
for (size_t i = 0; i < s.size(); i++) {
unsigned char ch = s[i];
if (ch == '\\' || ch == '\"') {
buf.push_back('\\');
buf.push_back(ch);
} else if (ch < ' ') {
char tmp[7];
sprintf(tmp, "\\u%04x", ch);
buf.append(std::string(tmp));
} else {
buf.push_back(ch);
}
}
return buf;
}
std::string mvt_value::toString() {
if (type == mvt_string) {
return quote(string_value);
} else if (type == mvt_int) {
return std::to_string((long long) numeric_value.int_value);
} else if (type == mvt_double) {
double v = numeric_value.double_value;
if (v == (long long) v) {
return std::to_string((long long) v);
} else {
return milo::dtoa_milo(v);
}
} else if (type == mvt_float) {
double v = numeric_value.float_value;
if (v == (long long) v) {
return std::to_string((long long) v);
} else {
return milo::dtoa_milo(v);
}
} else if (type == mvt_sint) {
return std::to_string((long long) numeric_value.sint_value);
} else if (type == mvt_uint) {
return std::to_string((long long) numeric_value.uint_value);
} else if (type == mvt_bool) {
return numeric_value.bool_value ? "true" : "false";
} else {
return "unknown";
}
}
void mvt_layer::tag(mvt_feature &feature, std::string key, mvt_value value) { void mvt_layer::tag(mvt_feature &feature, std::string key, mvt_value value) {
size_t ko, vo; size_t ko, vo;

View File

@ -79,6 +79,7 @@ struct mvt_value {
} numeric_value; } numeric_value;
bool operator<(const mvt_value &o) const; bool operator<(const mvt_value &o) const;
std::string toString();
}; };
struct mvt_layer { struct mvt_layer {